diff options
Diffstat (limited to 'arch/mips/kernel')
26 files changed, 551 insertions, 701 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 008a2fed0584..92987d1bbe5f 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
@@ -4,9 +4,10 @@ | |||
4 | 4 | ||
5 | extra-y := head.o vmlinux.lds | 5 | extra-y := head.o vmlinux.lds |
6 | 6 | ||
7 | obj-y += cpu-probe.o branch.o entry.o genex.o idle.o irq.o process.o \ | 7 | obj-y += cpu-probe.o branch.o elf.o entry.o genex.o idle.o irq.o \ |
8 | prom.o ptrace.o reset.o setup.o signal.o syscall.o \ | 8 | process.o prom.o ptrace.o reset.o setup.o signal.o \ |
9 | time.o topology.o traps.o unaligned.o watch.o vdso.o | 9 | syscall.o time.o topology.o traps.o unaligned.o watch.o \ |
10 | vdso.o | ||
10 | 11 | ||
11 | ifdef CONFIG_FUNCTION_TRACER | 12 | ifdef CONFIG_FUNCTION_TRACER |
12 | CFLAGS_REMOVE_ftrace.o = -pg | 13 | CFLAGS_REMOVE_ftrace.o = -pg |
@@ -18,12 +19,10 @@ endif | |||
18 | obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o | 19 | obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o |
19 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o | 20 | obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o |
20 | obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o | 21 | obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o |
21 | obj-$(CONFIG_CEVT_GIC) += cevt-gic.o | ||
22 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o | 22 | obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o |
23 | obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o | 23 | obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o |
24 | obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o | 24 | obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o |
25 | obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o | 25 | obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o |
26 | obj-$(CONFIG_CSRC_GIC) += csrc-gic.o | ||
27 | obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o | 26 | obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o |
28 | obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o | 27 | obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o |
29 | obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o | 28 | obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o |
@@ -68,7 +67,6 @@ obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o | |||
68 | obj-$(CONFIG_MIPS_MSC) += irq-msc01.o | 67 | obj-$(CONFIG_MIPS_MSC) += irq-msc01.o |
69 | obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o | 68 | obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o |
70 | obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o | 69 | obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o |
71 | obj-$(CONFIG_IRQ_GIC) += irq-gic.o | ||
72 | 70 | ||
73 | obj-$(CONFIG_KPROBES) += kprobes.o | 71 | obj-$(CONFIG_KPROBES) += kprobes.o |
74 | obj-$(CONFIG_32BIT) += scall32-o32.o | 72 | obj-$(CONFIG_32BIT) += scall32-o32.o |
diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c deleted file mode 100644 index 6093716980b9..000000000000 --- a/arch/mips/kernel/cevt-gic.c +++ /dev/null | |||
@@ -1,105 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2013 Imagination Technologies Ltd. | ||
7 | */ | ||
8 | #include <linux/clockchips.h> | ||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/percpu.h> | ||
11 | #include <linux/smp.h> | ||
12 | #include <linux/irq.h> | ||
13 | |||
14 | #include <asm/time.h> | ||
15 | #include <asm/gic.h> | ||
16 | #include <asm/mips-boards/maltaint.h> | ||
17 | |||
18 | DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device); | ||
19 | int gic_timer_irq_installed; | ||
20 | |||
21 | |||
22 | static int gic_next_event(unsigned long delta, struct clock_event_device *evt) | ||
23 | { | ||
24 | u64 cnt; | ||
25 | int res; | ||
26 | |||
27 | cnt = gic_read_count(); | ||
28 | cnt += (u64)delta; | ||
29 | gic_write_cpu_compare(cnt, cpumask_first(evt->cpumask)); | ||
30 | res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0; | ||
31 | return res; | ||
32 | } | ||
33 | |||
34 | void gic_set_clock_mode(enum clock_event_mode mode, | ||
35 | struct clock_event_device *evt) | ||
36 | { | ||
37 | /* Nothing to do ... */ | ||
38 | } | ||
39 | |||
40 | irqreturn_t gic_compare_interrupt(int irq, void *dev_id) | ||
41 | { | ||
42 | struct clock_event_device *cd; | ||
43 | int cpu = smp_processor_id(); | ||
44 | |||
45 | gic_write_compare(gic_read_compare()); | ||
46 | cd = &per_cpu(gic_clockevent_device, cpu); | ||
47 | cd->event_handler(cd); | ||
48 | return IRQ_HANDLED; | ||
49 | } | ||
50 | |||
51 | struct irqaction gic_compare_irqaction = { | ||
52 | .handler = gic_compare_interrupt, | ||
53 | .flags = IRQF_PERCPU | IRQF_TIMER, | ||
54 | .name = "timer", | ||
55 | }; | ||
56 | |||
57 | |||
58 | void gic_event_handler(struct clock_event_device *dev) | ||
59 | { | ||
60 | } | ||
61 | |||
62 | int gic_clockevent_init(void) | ||
63 | { | ||
64 | unsigned int cpu = smp_processor_id(); | ||
65 | struct clock_event_device *cd; | ||
66 | unsigned int irq; | ||
67 | |||
68 | if (!cpu_has_counter || !gic_frequency) | ||
69 | return -ENXIO; | ||
70 | |||
71 | irq = MIPS_GIC_IRQ_BASE; | ||
72 | |||
73 | cd = &per_cpu(gic_clockevent_device, cpu); | ||
74 | |||
75 | cd->name = "MIPS GIC"; | ||
76 | cd->features = CLOCK_EVT_FEAT_ONESHOT | | ||
77 | CLOCK_EVT_FEAT_C3STOP; | ||
78 | |||
79 | clockevent_set_clock(cd, gic_frequency); | ||
80 | |||
81 | /* Calculate the min / max delta */ | ||
82 | cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); | ||
83 | cd->min_delta_ns = clockevent_delta2ns(0x300, cd); | ||
84 | |||
85 | cd->rating = 300; | ||
86 | cd->irq = irq; | ||
87 | cd->cpumask = cpumask_of(cpu); | ||
88 | cd->set_next_event = gic_next_event; | ||
89 | cd->set_mode = gic_set_clock_mode; | ||
90 | cd->event_handler = gic_event_handler; | ||
91 | |||
92 | clockevents_register_device(cd); | ||
93 | |||
94 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002); | ||
95 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK); | ||
96 | |||
97 | if (gic_timer_irq_installed) | ||
98 | return 0; | ||
99 | |||
100 | gic_timer_irq_installed = 1; | ||
101 | |||
102 | setup_irq(irq, &gic_compare_irqaction); | ||
103 | irq_set_handler(irq, handle_percpu_irq); | ||
104 | return 0; | ||
105 | } | ||
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index bc127e22fdab..6acaad0480af 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c | |||
@@ -11,10 +11,10 @@ | |||
11 | #include <linux/percpu.h> | 11 | #include <linux/percpu.h> |
12 | #include <linux/smp.h> | 12 | #include <linux/smp.h> |
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | #include <linux/irqchip/mips-gic.h> | ||
14 | 15 | ||
15 | #include <asm/time.h> | 16 | #include <asm/time.h> |
16 | #include <asm/cevt-r4k.h> | 17 | #include <asm/cevt-r4k.h> |
17 | #include <asm/gic.h> | ||
18 | 18 | ||
19 | static int mips_next_event(unsigned long delta, | 19 | static int mips_next_event(unsigned long delta, |
20 | struct clock_event_device *evt) | 20 | struct clock_event_device *evt) |
@@ -85,8 +85,8 @@ void mips_event_handler(struct clock_event_device *dev) | |||
85 | */ | 85 | */ |
86 | static int c0_compare_int_pending(void) | 86 | static int c0_compare_int_pending(void) |
87 | { | 87 | { |
88 | #ifdef CONFIG_IRQ_GIC | 88 | #ifdef CONFIG_MIPS_GIC |
89 | if (cpu_has_veic) | 89 | if (gic_present) |
90 | return gic_get_timer_pending(); | 90 | return gic_get_timer_pending(); |
91 | #endif | 91 | #endif |
92 | return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP); | 92 | return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP); |
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index dc49cf30c2db..5342674842f5 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
@@ -69,6 +69,63 @@ static int __init htw_disable(char *s) | |||
69 | 69 | ||
70 | __setup("nohtw", htw_disable); | 70 | __setup("nohtw", htw_disable); |
71 | 71 | ||
72 | static int mips_ftlb_disabled; | ||
73 | static int mips_has_ftlb_configured; | ||
74 | |||
75 | static void set_ftlb_enable(struct cpuinfo_mips *c, int enable); | ||
76 | |||
77 | static int __init ftlb_disable(char *s) | ||
78 | { | ||
79 | unsigned int config4, mmuextdef; | ||
80 | |||
81 | /* | ||
82 | * If the core hasn't done any FTLB configuration, there is nothing | ||
83 | * for us to do here. | ||
84 | */ | ||
85 | if (!mips_has_ftlb_configured) | ||
86 | return 1; | ||
87 | |||
88 | /* Disable it in the boot cpu */ | ||
89 | set_ftlb_enable(&cpu_data[0], 0); | ||
90 | |||
91 | back_to_back_c0_hazard(); | ||
92 | |||
93 | config4 = read_c0_config4(); | ||
94 | |||
95 | /* Check that FTLB has been disabled */ | ||
96 | mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; | ||
97 | /* MMUSIZEEXT == VTLB ON, FTLB OFF */ | ||
98 | if (mmuextdef == MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT) { | ||
99 | /* This should never happen */ | ||
100 | pr_warn("FTLB could not be disabled!\n"); | ||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | mips_ftlb_disabled = 1; | ||
105 | mips_has_ftlb_configured = 0; | ||
106 | |||
107 | /* | ||
108 | * noftlb is mainly used for debug purposes so print | ||
109 | * an informative message instead of using pr_debug() | ||
110 | */ | ||
111 | pr_info("FTLB has been disabled\n"); | ||
112 | |||
113 | /* | ||
114 | * Some of these bits are duplicated in the decode_config4. | ||
115 | * MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT is the only possible case | ||
116 | * once FTLB has been disabled so undo what decode_config4 did. | ||
117 | */ | ||
118 | cpu_data[0].tlbsize -= cpu_data[0].tlbsizeftlbways * | ||
119 | cpu_data[0].tlbsizeftlbsets; | ||
120 | cpu_data[0].tlbsizeftlbsets = 0; | ||
121 | cpu_data[0].tlbsizeftlbways = 0; | ||
122 | |||
123 | return 1; | ||
124 | } | ||
125 | |||
126 | __setup("noftlb", ftlb_disable); | ||
127 | |||
128 | |||
72 | static inline void check_errata(void) | 129 | static inline void check_errata(void) |
73 | { | 130 | { |
74 | struct cpuinfo_mips *c = ¤t_cpu_data; | 131 | struct cpuinfo_mips *c = ¤t_cpu_data; |
@@ -140,7 +197,7 @@ static inline unsigned long cpu_get_fpu_id(void) | |||
140 | */ | 197 | */ |
141 | static inline int __cpu_has_fpu(void) | 198 | static inline int __cpu_has_fpu(void) |
142 | { | 199 | { |
143 | return ((cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE); | 200 | return (cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE; |
144 | } | 201 | } |
145 | 202 | ||
146 | static inline unsigned long cpu_get_msa_id(void) | 203 | static inline unsigned long cpu_get_msa_id(void) |
@@ -399,6 +456,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) | |||
399 | ftlb_page = MIPS_CONF4_VFTLBPAGESIZE; | 456 | ftlb_page = MIPS_CONF4_VFTLBPAGESIZE; |
400 | /* fall through */ | 457 | /* fall through */ |
401 | case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT: | 458 | case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT: |
459 | if (mips_ftlb_disabled) | ||
460 | break; | ||
402 | newcf4 = (config4 & ~ftlb_page) | | 461 | newcf4 = (config4 & ~ftlb_page) | |
403 | (page_size_ftlb(mmuextdef) << | 462 | (page_size_ftlb(mmuextdef) << |
404 | MIPS_CONF4_FTLBPAGESIZE_SHIFT); | 463 | MIPS_CONF4_FTLBPAGESIZE_SHIFT); |
@@ -418,6 +477,7 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) | |||
418 | c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >> | 477 | c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >> |
419 | MIPS_CONF4_FTLBWAYS_SHIFT) + 2; | 478 | MIPS_CONF4_FTLBWAYS_SHIFT) + 2; |
420 | c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets; | 479 | c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets; |
480 | mips_has_ftlb_configured = 1; | ||
421 | break; | 481 | break; |
422 | } | 482 | } |
423 | } | 483 | } |
@@ -432,7 +492,7 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) | |||
432 | unsigned int config5; | 492 | unsigned int config5; |
433 | 493 | ||
434 | config5 = read_c0_config5(); | 494 | config5 = read_c0_config5(); |
435 | config5 &= ~MIPS_CONF5_UFR; | 495 | config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE); |
436 | write_c0_config5(config5); | 496 | write_c0_config5(config5); |
437 | 497 | ||
438 | if (config5 & MIPS_CONF5_EVA) | 498 | if (config5 & MIPS_CONF5_EVA) |
@@ -453,8 +513,8 @@ static void decode_configs(struct cpuinfo_mips *c) | |||
453 | 513 | ||
454 | c->scache.flags = MIPS_CACHE_NOT_PRESENT; | 514 | c->scache.flags = MIPS_CACHE_NOT_PRESENT; |
455 | 515 | ||
456 | /* Enable FTLB if present */ | 516 | /* Enable FTLB if present and not disabled */ |
457 | set_ftlb_enable(c, 1); | 517 | set_ftlb_enable(c, !mips_ftlb_disabled); |
458 | 518 | ||
459 | ok = decode_config0(c); /* Read Config registers. */ | 519 | ok = decode_config0(c); /* Read Config registers. */ |
460 | BUG_ON(!ok); /* Arch spec violation! */ | 520 | BUG_ON(!ok); /* Arch spec violation! */ |
@@ -1058,6 +1118,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) | |||
1058 | break; | 1118 | break; |
1059 | } | 1119 | } |
1060 | case PRID_IMP_BMIPS5000: | 1120 | case PRID_IMP_BMIPS5000: |
1121 | case PRID_IMP_BMIPS5200: | ||
1061 | c->cputype = CPU_BMIPS5000; | 1122 | c->cputype = CPU_BMIPS5000; |
1062 | __cpu_name[cpu] = "Broadcom BMIPS5000"; | 1123 | __cpu_name[cpu] = "Broadcom BMIPS5000"; |
1063 | set_elf_platform(cpu, "bmips5000"); | 1124 | set_elf_platform(cpu, "bmips5000"); |
@@ -1288,6 +1349,8 @@ void cpu_probe(void) | |||
1288 | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) { | 1349 | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) { |
1289 | if (c->fpu_id & MIPS_FPIR_3D) | 1350 | if (c->fpu_id & MIPS_FPIR_3D) |
1290 | c->ases |= MIPS_ASE_MIPS3D; | 1351 | c->ases |= MIPS_ASE_MIPS3D; |
1352 | if (c->fpu_id & MIPS_FPIR_FREP) | ||
1353 | c->options |= MIPS_CPU_FRE; | ||
1291 | } | 1354 | } |
1292 | } | 1355 | } |
1293 | 1356 | ||
diff --git a/arch/mips/kernel/crash_dump.c b/arch/mips/kernel/crash_dump.c index f291cf99b03a..6fe7790e5868 100644 --- a/arch/mips/kernel/crash_dump.c +++ b/arch/mips/kernel/crash_dump.c | |||
@@ -38,7 +38,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, | |||
38 | kunmap_atomic(vaddr); | 38 | kunmap_atomic(vaddr); |
39 | } else { | 39 | } else { |
40 | if (!kdump_buf_page) { | 40 | if (!kdump_buf_page) { |
41 | pr_warning("Kdump: Kdump buffer page not allocated\n"); | 41 | pr_warn("Kdump: Kdump buffer page not allocated\n"); |
42 | 42 | ||
43 | return -EFAULT; | 43 | return -EFAULT; |
44 | } | 44 | } |
@@ -57,7 +57,7 @@ static int __init kdump_buf_page_init(void) | |||
57 | 57 | ||
58 | kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL); | 58 | kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL); |
59 | if (!kdump_buf_page) { | 59 | if (!kdump_buf_page) { |
60 | pr_warning("Kdump: Failed to allocate kdump buffer page\n"); | 60 | pr_warn("Kdump: Failed to allocate kdump buffer page\n"); |
61 | ret = -ENOMEM; | 61 | ret = -ENOMEM; |
62 | } | 62 | } |
63 | 63 | ||
diff --git a/arch/mips/kernel/csrc-gic.c b/arch/mips/kernel/csrc-gic.c deleted file mode 100644 index e02620901117..000000000000 --- a/arch/mips/kernel/csrc-gic.c +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. | ||
7 | */ | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/time.h> | ||
10 | |||
11 | #include <asm/gic.h> | ||
12 | |||
13 | static cycle_t gic_hpt_read(struct clocksource *cs) | ||
14 | { | ||
15 | return gic_read_count(); | ||
16 | } | ||
17 | |||
18 | static struct clocksource gic_clocksource = { | ||
19 | .name = "GIC", | ||
20 | .read = gic_hpt_read, | ||
21 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
22 | }; | ||
23 | |||
24 | void __init gic_clocksource_init(unsigned int frequency) | ||
25 | { | ||
26 | unsigned int config, bits; | ||
27 | |||
28 | /* Calculate the clocksource mask. */ | ||
29 | GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), config); | ||
30 | bits = 32 + ((config & GIC_SH_CONFIG_COUNTBITS_MSK) >> | ||
31 | (GIC_SH_CONFIG_COUNTBITS_SHF - 2)); | ||
32 | |||
33 | /* Set clocksource mask. */ | ||
34 | gic_clocksource.mask = CLOCKSOURCE_MASK(bits); | ||
35 | |||
36 | /* Calculate a somewhat reasonable rating value. */ | ||
37 | gic_clocksource.rating = 200 + frequency / 10000000; | ||
38 | |||
39 | clocksource_register_hz(&gic_clocksource, frequency); | ||
40 | } | ||
diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c new file mode 100644 index 000000000000..c92b15df6893 --- /dev/null +++ b/arch/mips/kernel/elf.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Imagination Technologies | ||
3 | * Author: Paul Burton <paul.burton@imgtec.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/elf.h> | ||
12 | #include <linux/sched.h> | ||
13 | |||
14 | enum { | ||
15 | FP_ERROR = -1, | ||
16 | FP_DOUBLE_64A = -2, | ||
17 | }; | ||
18 | |||
19 | int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, | ||
20 | bool is_interp, struct arch_elf_state *state) | ||
21 | { | ||
22 | struct elfhdr *ehdr = _ehdr; | ||
23 | struct elf_phdr *phdr = _phdr; | ||
24 | struct mips_elf_abiflags_v0 abiflags; | ||
25 | int ret; | ||
26 | |||
27 | if (config_enabled(CONFIG_64BIT) && | ||
28 | (ehdr->e_ident[EI_CLASS] != ELFCLASS32)) | ||
29 | return 0; | ||
30 | if (phdr->p_type != PT_MIPS_ABIFLAGS) | ||
31 | return 0; | ||
32 | if (phdr->p_filesz < sizeof(abiflags)) | ||
33 | return -EINVAL; | ||
34 | |||
35 | ret = kernel_read(elf, phdr->p_offset, (char *)&abiflags, | ||
36 | sizeof(abiflags)); | ||
37 | if (ret < 0) | ||
38 | return ret; | ||
39 | if (ret != sizeof(abiflags)) | ||
40 | return -EIO; | ||
41 | |||
42 | /* Record the required FP ABIs for use by mips_check_elf */ | ||
43 | if (is_interp) | ||
44 | state->interp_fp_abi = abiflags.fp_abi; | ||
45 | else | ||
46 | state->fp_abi = abiflags.fp_abi; | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static inline unsigned get_fp_abi(struct elfhdr *ehdr, int in_abi) | ||
52 | { | ||
53 | /* If the ABI requirement is provided, simply return that */ | ||
54 | if (in_abi != -1) | ||
55 | return in_abi; | ||
56 | |||
57 | /* If the EF_MIPS_FP64 flag was set, return MIPS_ABI_FP_64 */ | ||
58 | if (ehdr->e_flags & EF_MIPS_FP64) | ||
59 | return MIPS_ABI_FP_64; | ||
60 | |||
61 | /* Default to MIPS_ABI_FP_DOUBLE */ | ||
62 | return MIPS_ABI_FP_DOUBLE; | ||
63 | } | ||
64 | |||
65 | int arch_check_elf(void *_ehdr, bool has_interpreter, | ||
66 | struct arch_elf_state *state) | ||
67 | { | ||
68 | struct elfhdr *ehdr = _ehdr; | ||
69 | unsigned fp_abi, interp_fp_abi, abi0, abi1; | ||
70 | |||
71 | /* Ignore non-O32 binaries */ | ||
72 | if (config_enabled(CONFIG_64BIT) && | ||
73 | (ehdr->e_ident[EI_CLASS] != ELFCLASS32)) | ||
74 | return 0; | ||
75 | |||
76 | fp_abi = get_fp_abi(ehdr, state->fp_abi); | ||
77 | |||
78 | if (has_interpreter) { | ||
79 | interp_fp_abi = get_fp_abi(ehdr, state->interp_fp_abi); | ||
80 | |||
81 | abi0 = min(fp_abi, interp_fp_abi); | ||
82 | abi1 = max(fp_abi, interp_fp_abi); | ||
83 | } else { | ||
84 | abi0 = abi1 = fp_abi; | ||
85 | } | ||
86 | |||
87 | state->overall_abi = FP_ERROR; | ||
88 | |||
89 | if (abi0 == abi1) { | ||
90 | state->overall_abi = abi0; | ||
91 | } else if (abi0 == MIPS_ABI_FP_ANY) { | ||
92 | state->overall_abi = abi1; | ||
93 | } else if (abi0 == MIPS_ABI_FP_DOUBLE) { | ||
94 | switch (abi1) { | ||
95 | case MIPS_ABI_FP_XX: | ||
96 | state->overall_abi = MIPS_ABI_FP_DOUBLE; | ||
97 | break; | ||
98 | |||
99 | case MIPS_ABI_FP_64A: | ||
100 | state->overall_abi = FP_DOUBLE_64A; | ||
101 | break; | ||
102 | } | ||
103 | } else if (abi0 == MIPS_ABI_FP_SINGLE || | ||
104 | abi0 == MIPS_ABI_FP_SOFT) { | ||
105 | /* Cannot link with other ABIs */ | ||
106 | } else if (abi0 == MIPS_ABI_FP_OLD_64) { | ||
107 | switch (abi1) { | ||
108 | case MIPS_ABI_FP_XX: | ||
109 | case MIPS_ABI_FP_64: | ||
110 | case MIPS_ABI_FP_64A: | ||
111 | state->overall_abi = MIPS_ABI_FP_64; | ||
112 | break; | ||
113 | } | ||
114 | } else if (abi0 == MIPS_ABI_FP_XX || | ||
115 | abi0 == MIPS_ABI_FP_64 || | ||
116 | abi0 == MIPS_ABI_FP_64A) { | ||
117 | state->overall_abi = MIPS_ABI_FP_64; | ||
118 | } | ||
119 | |||
120 | switch (state->overall_abi) { | ||
121 | case MIPS_ABI_FP_64: | ||
122 | case MIPS_ABI_FP_64A: | ||
123 | case FP_DOUBLE_64A: | ||
124 | if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) | ||
125 | return -ELIBBAD; | ||
126 | break; | ||
127 | |||
128 | case FP_ERROR: | ||
129 | return -ELIBBAD; | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | void mips_set_personality_fp(struct arch_elf_state *state) | ||
136 | { | ||
137 | if (config_enabled(CONFIG_FP32XX_HYBRID_FPRS)) { | ||
138 | /* | ||
139 | * Use hybrid FPRs for all code which can correctly execute | ||
140 | * with that mode. | ||
141 | */ | ||
142 | switch (state->overall_abi) { | ||
143 | case MIPS_ABI_FP_DOUBLE: | ||
144 | case MIPS_ABI_FP_SINGLE: | ||
145 | case MIPS_ABI_FP_SOFT: | ||
146 | case MIPS_ABI_FP_XX: | ||
147 | case MIPS_ABI_FP_ANY: | ||
148 | /* FR=1, FRE=1 */ | ||
149 | clear_thread_flag(TIF_32BIT_FPREGS); | ||
150 | set_thread_flag(TIF_HYBRID_FPREGS); | ||
151 | return; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | switch (state->overall_abi) { | ||
156 | case MIPS_ABI_FP_DOUBLE: | ||
157 | case MIPS_ABI_FP_SINGLE: | ||
158 | case MIPS_ABI_FP_SOFT: | ||
159 | /* FR=0 */ | ||
160 | set_thread_flag(TIF_32BIT_FPREGS); | ||
161 | clear_thread_flag(TIF_HYBRID_FPREGS); | ||
162 | break; | ||
163 | |||
164 | case FP_DOUBLE_64A: | ||
165 | /* FR=1, FRE=1 */ | ||
166 | clear_thread_flag(TIF_32BIT_FPREGS); | ||
167 | set_thread_flag(TIF_HYBRID_FPREGS); | ||
168 | break; | ||
169 | |||
170 | case MIPS_ABI_FP_64: | ||
171 | case MIPS_ABI_FP_64A: | ||
172 | /* FR=1, FRE=0 */ | ||
173 | clear_thread_flag(TIF_32BIT_FPREGS); | ||
174 | clear_thread_flag(TIF_HYBRID_FPREGS); | ||
175 | break; | ||
176 | |||
177 | case MIPS_ABI_FP_XX: | ||
178 | case MIPS_ABI_FP_ANY: | ||
179 | if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) | ||
180 | set_thread_flag(TIF_32BIT_FPREGS); | ||
181 | else | ||
182 | clear_thread_flag(TIF_32BIT_FPREGS); | ||
183 | |||
184 | clear_thread_flag(TIF_HYBRID_FPREGS); | ||
185 | break; | ||
186 | |||
187 | default: | ||
188 | case FP_ERROR: | ||
189 | BUG(); | ||
190 | } | ||
191 | } | ||
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 50b364897dda..a74ec3ae557c 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/ioport.h> | 13 | #include <linux/ioport.h> |
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/irqdomain.h> | ||
15 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
16 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
17 | #include <linux/syscore_ops.h> | 18 | #include <linux/syscore_ops.h> |
@@ -308,6 +309,19 @@ static struct resource pic2_io_resource = { | |||
308 | .flags = IORESOURCE_BUSY | 309 | .flags = IORESOURCE_BUSY |
309 | }; | 310 | }; |
310 | 311 | ||
312 | static int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq, | ||
313 | irq_hw_number_t hw) | ||
314 | { | ||
315 | irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq); | ||
316 | irq_set_probe(virq); | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static struct irq_domain_ops i8259A_ops = { | ||
321 | .map = i8259A_irq_domain_map, | ||
322 | .xlate = irq_domain_xlate_onecell, | ||
323 | }; | ||
324 | |||
311 | /* | 325 | /* |
312 | * On systems with i8259-style interrupt controllers we assume for | 326 | * On systems with i8259-style interrupt controllers we assume for |
313 | * driver compatibility reasons interrupts 0 - 15 to be the i8259 | 327 | * driver compatibility reasons interrupts 0 - 15 to be the i8259 |
@@ -315,17 +329,17 @@ static struct resource pic2_io_resource = { | |||
315 | */ | 329 | */ |
316 | void __init init_i8259_irqs(void) | 330 | void __init init_i8259_irqs(void) |
317 | { | 331 | { |
318 | int i; | 332 | struct irq_domain *domain; |
319 | 333 | ||
320 | insert_resource(&ioport_resource, &pic1_io_resource); | 334 | insert_resource(&ioport_resource, &pic1_io_resource); |
321 | insert_resource(&ioport_resource, &pic2_io_resource); | 335 | insert_resource(&ioport_resource, &pic2_io_resource); |
322 | 336 | ||
323 | init_8259A(0); | 337 | init_8259A(0); |
324 | 338 | ||
325 | for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) { | 339 | domain = irq_domain_add_legacy(NULL, 16, I8259A_IRQ_BASE, 0, |
326 | irq_set_chip_and_handler(i, &i8259A_chip, handle_level_irq); | 340 | &i8259A_ops, NULL); |
327 | irq_set_probe(i); | 341 | if (!domain) |
328 | } | 342 | panic("Failed to add i8259 IRQ domain"); |
329 | 343 | ||
330 | setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); | 344 | setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); |
331 | } | 345 | } |
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c deleted file mode 100644 index 9e9d8b9a5b97..000000000000 --- a/arch/mips/kernel/irq-gic.c +++ /dev/null | |||
@@ -1,402 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org) | ||
7 | * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. | ||
8 | */ | ||
9 | #include <linux/bitmap.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/smp.h> | ||
12 | #include <linux/irq.h> | ||
13 | #include <linux/clocksource.h> | ||
14 | |||
15 | #include <asm/io.h> | ||
16 | #include <asm/gic.h> | ||
17 | #include <asm/setup.h> | ||
18 | #include <asm/traps.h> | ||
19 | #include <linux/hardirq.h> | ||
20 | #include <asm-generic/bitops/find.h> | ||
21 | |||
22 | unsigned int gic_frequency; | ||
23 | unsigned int gic_present; | ||
24 | unsigned long _gic_base; | ||
25 | unsigned int gic_irq_base; | ||
26 | unsigned int gic_irq_flags[GIC_NUM_INTRS]; | ||
27 | |||
28 | /* The index into this array is the vector # of the interrupt. */ | ||
29 | struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS]; | ||
30 | |||
31 | struct gic_pcpu_mask { | ||
32 | DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS); | ||
33 | }; | ||
34 | |||
35 | struct gic_pending_regs { | ||
36 | DECLARE_BITMAP(pending, GIC_NUM_INTRS); | ||
37 | }; | ||
38 | |||
39 | struct gic_intrmask_regs { | ||
40 | DECLARE_BITMAP(intrmask, GIC_NUM_INTRS); | ||
41 | }; | ||
42 | |||
43 | static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; | ||
44 | static struct gic_pending_regs pending_regs[NR_CPUS]; | ||
45 | static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; | ||
46 | |||
47 | #if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC) | ||
48 | cycle_t gic_read_count(void) | ||
49 | { | ||
50 | unsigned int hi, hi2, lo; | ||
51 | |||
52 | do { | ||
53 | GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi); | ||
54 | GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo); | ||
55 | GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2); | ||
56 | } while (hi2 != hi); | ||
57 | |||
58 | return (((cycle_t) hi) << 32) + lo; | ||
59 | } | ||
60 | |||
61 | void gic_write_compare(cycle_t cnt) | ||
62 | { | ||
63 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), | ||
64 | (int)(cnt >> 32)); | ||
65 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), | ||
66 | (int)(cnt & 0xffffffff)); | ||
67 | } | ||
68 | |||
69 | void gic_write_cpu_compare(cycle_t cnt, int cpu) | ||
70 | { | ||
71 | unsigned long flags; | ||
72 | |||
73 | local_irq_save(flags); | ||
74 | |||
75 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); | ||
76 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), | ||
77 | (int)(cnt >> 32)); | ||
78 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), | ||
79 | (int)(cnt & 0xffffffff)); | ||
80 | |||
81 | local_irq_restore(flags); | ||
82 | } | ||
83 | |||
84 | cycle_t gic_read_compare(void) | ||
85 | { | ||
86 | unsigned int hi, lo; | ||
87 | |||
88 | GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), hi); | ||
89 | GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), lo); | ||
90 | |||
91 | return (((cycle_t) hi) << 32) + lo; | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | unsigned int gic_get_timer_pending(void) | ||
96 | { | ||
97 | unsigned int vpe_pending; | ||
98 | |||
99 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0); | ||
100 | GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending); | ||
101 | return (vpe_pending & GIC_VPE_PEND_TIMER_MSK); | ||
102 | } | ||
103 | |||
104 | void gic_bind_eic_interrupt(int irq, int set) | ||
105 | { | ||
106 | /* Convert irq vector # to hw int # */ | ||
107 | irq -= GIC_PIN_TO_VEC_OFFSET; | ||
108 | |||
109 | /* Set irq to use shadow set */ | ||
110 | GICWRITE(GIC_REG_ADDR(VPE_LOCAL, GIC_VPE_EIC_SS(irq)), set); | ||
111 | } | ||
112 | |||
113 | void gic_send_ipi(unsigned int intr) | ||
114 | { | ||
115 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); | ||
116 | } | ||
117 | |||
118 | static void gic_eic_irq_dispatch(void) | ||
119 | { | ||
120 | unsigned int cause = read_c0_cause(); | ||
121 | int irq; | ||
122 | |||
123 | irq = (cause & ST0_IM) >> STATUSB_IP2; | ||
124 | if (irq == 0) | ||
125 | irq = -1; | ||
126 | |||
127 | if (irq >= 0) | ||
128 | do_IRQ(gic_irq_base + irq); | ||
129 | else | ||
130 | spurious_interrupt(); | ||
131 | } | ||
132 | |||
133 | static void __init vpe_local_setup(unsigned int numvpes) | ||
134 | { | ||
135 | unsigned long timer_intr = GIC_INT_TMR; | ||
136 | unsigned long perf_intr = GIC_INT_PERFCTR; | ||
137 | unsigned int vpe_ctl; | ||
138 | int i; | ||
139 | |||
140 | if (cpu_has_veic) { | ||
141 | /* | ||
142 | * GIC timer interrupt -> CPU HW Int X (vector X+2) -> | ||
143 | * map to pin X+2-1 (since GIC adds 1) | ||
144 | */ | ||
145 | timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); | ||
146 | /* | ||
147 | * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) -> | ||
148 | * map to pin X+2-1 (since GIC adds 1) | ||
149 | */ | ||
150 | perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Setup the default performance counter timer interrupts | ||
155 | * for all VPEs | ||
156 | */ | ||
157 | for (i = 0; i < numvpes; i++) { | ||
158 | GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); | ||
159 | |||
160 | /* Are Interrupts locally routable? */ | ||
161 | GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); | ||
162 | if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) | ||
163 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), | ||
164 | GIC_MAP_TO_PIN_MSK | timer_intr); | ||
165 | if (cpu_has_veic) { | ||
166 | set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET, | ||
167 | gic_eic_irq_dispatch); | ||
168 | gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK; | ||
169 | } | ||
170 | |||
171 | if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) | ||
172 | GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), | ||
173 | GIC_MAP_TO_PIN_MSK | perf_intr); | ||
174 | if (cpu_has_veic) { | ||
175 | set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch); | ||
176 | gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK; | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | unsigned int gic_compare_int(void) | ||
182 | { | ||
183 | unsigned int pending; | ||
184 | |||
185 | GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending); | ||
186 | if (pending & GIC_VPE_PEND_CMP_MSK) | ||
187 | return 1; | ||
188 | else | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | void gic_get_int_mask(unsigned long *dst, const unsigned long *src) | ||
193 | { | ||
194 | unsigned int i; | ||
195 | unsigned long *pending, *intrmask, *pcpu_mask; | ||
196 | unsigned long *pending_abs, *intrmask_abs; | ||
197 | |||
198 | /* Get per-cpu bitmaps */ | ||
199 | pending = pending_regs[smp_processor_id()].pending; | ||
200 | intrmask = intrmask_regs[smp_processor_id()].intrmask; | ||
201 | pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask; | ||
202 | |||
203 | pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, | ||
204 | GIC_SH_PEND_31_0_OFS); | ||
205 | intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, | ||
206 | GIC_SH_MASK_31_0_OFS); | ||
207 | |||
208 | for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) { | ||
209 | GICREAD(*pending_abs, pending[i]); | ||
210 | GICREAD(*intrmask_abs, intrmask[i]); | ||
211 | pending_abs++; | ||
212 | intrmask_abs++; | ||
213 | } | ||
214 | |||
215 | bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS); | ||
216 | bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS); | ||
217 | bitmap_and(dst, src, pending, GIC_NUM_INTRS); | ||
218 | } | ||
219 | |||
220 | unsigned int gic_get_int(void) | ||
221 | { | ||
222 | DECLARE_BITMAP(interrupts, GIC_NUM_INTRS); | ||
223 | |||
224 | bitmap_fill(interrupts, GIC_NUM_INTRS); | ||
225 | gic_get_int_mask(interrupts, interrupts); | ||
226 | |||
227 | return find_first_bit(interrupts, GIC_NUM_INTRS); | ||
228 | } | ||
229 | |||
230 | static void gic_mask_irq(struct irq_data *d) | ||
231 | { | ||
232 | GIC_CLR_INTR_MASK(d->irq - gic_irq_base); | ||
233 | } | ||
234 | |||
235 | static void gic_unmask_irq(struct irq_data *d) | ||
236 | { | ||
237 | GIC_SET_INTR_MASK(d->irq - gic_irq_base); | ||
238 | } | ||
239 | |||
240 | #ifdef CONFIG_SMP | ||
241 | static DEFINE_SPINLOCK(gic_lock); | ||
242 | |||
243 | static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, | ||
244 | bool force) | ||
245 | { | ||
246 | unsigned int irq = (d->irq - gic_irq_base); | ||
247 | cpumask_t tmp = CPU_MASK_NONE; | ||
248 | unsigned long flags; | ||
249 | int i; | ||
250 | |||
251 | cpumask_and(&tmp, cpumask, cpu_online_mask); | ||
252 | if (cpus_empty(tmp)) | ||
253 | return -1; | ||
254 | |||
255 | /* Assumption : cpumask refers to a single CPU */ | ||
256 | spin_lock_irqsave(&gic_lock, flags); | ||
257 | |||
258 | /* Re-route this IRQ */ | ||
259 | GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp)); | ||
260 | |||
261 | /* Update the pcpu_masks */ | ||
262 | for (i = 0; i < NR_CPUS; i++) | ||
263 | clear_bit(irq, pcpu_masks[i].pcpu_mask); | ||
264 | set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); | ||
265 | |||
266 | cpumask_copy(d->affinity, cpumask); | ||
267 | spin_unlock_irqrestore(&gic_lock, flags); | ||
268 | |||
269 | return IRQ_SET_MASK_OK_NOCOPY; | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | static struct irq_chip gic_irq_controller = { | ||
274 | .name = "MIPS GIC", | ||
275 | .irq_ack = gic_irq_ack, | ||
276 | .irq_mask = gic_mask_irq, | ||
277 | .irq_mask_ack = gic_mask_irq, | ||
278 | .irq_unmask = gic_unmask_irq, | ||
279 | .irq_eoi = gic_finish_irq, | ||
280 | #ifdef CONFIG_SMP | ||
281 | .irq_set_affinity = gic_set_affinity, | ||
282 | #endif | ||
283 | }; | ||
284 | |||
285 | static void __init gic_setup_intr(unsigned int intr, unsigned int cpu, | ||
286 | unsigned int pin, unsigned int polarity, unsigned int trigtype, | ||
287 | unsigned int flags) | ||
288 | { | ||
289 | struct gic_shared_intr_map *map_ptr; | ||
290 | |||
291 | /* Setup Intr to Pin mapping */ | ||
292 | if (pin & GIC_MAP_TO_NMI_MSK) { | ||
293 | int i; | ||
294 | |||
295 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); | ||
296 | /* FIXME: hack to route NMI to all cpu's */ | ||
297 | for (i = 0; i < NR_CPUS; i += 32) { | ||
298 | GICWRITE(GIC_REG_ADDR(SHARED, | ||
299 | GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)), | ||
300 | 0xffffffff); | ||
301 | } | ||
302 | } else { | ||
303 | GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), | ||
304 | GIC_MAP_TO_PIN_MSK | pin); | ||
305 | /* Setup Intr to CPU mapping */ | ||
306 | GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); | ||
307 | if (cpu_has_veic) { | ||
308 | set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET, | ||
309 | gic_eic_irq_dispatch); | ||
310 | map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET]; | ||
311 | if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR) | ||
312 | BUG(); | ||
313 | map_ptr->intr_list[map_ptr->num_shared_intr++] = intr; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | /* Setup Intr Polarity */ | ||
318 | GIC_SET_POLARITY(intr, polarity); | ||
319 | |||
320 | /* Setup Intr Trigger Type */ | ||
321 | GIC_SET_TRIGGER(intr, trigtype); | ||
322 | |||
323 | /* Init Intr Masks */ | ||
324 | GIC_CLR_INTR_MASK(intr); | ||
325 | |||
326 | /* Initialise per-cpu Interrupt software masks */ | ||
327 | set_bit(intr, pcpu_masks[cpu].pcpu_mask); | ||
328 | |||
329 | if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0)) | ||
330 | GIC_SET_INTR_MASK(intr); | ||
331 | if (trigtype == GIC_TRIG_EDGE) | ||
332 | gic_irq_flags[intr] |= GIC_TRIG_EDGE; | ||
333 | } | ||
334 | |||
335 | static void __init gic_basic_init(int numintrs, int numvpes, | ||
336 | struct gic_intr_map *intrmap, int mapsize) | ||
337 | { | ||
338 | unsigned int i, cpu; | ||
339 | unsigned int pin_offset = 0; | ||
340 | |||
341 | board_bind_eic_interrupt = &gic_bind_eic_interrupt; | ||
342 | |||
343 | /* Setup defaults */ | ||
344 | for (i = 0; i < numintrs; i++) { | ||
345 | GIC_SET_POLARITY(i, GIC_POL_POS); | ||
346 | GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL); | ||
347 | GIC_CLR_INTR_MASK(i); | ||
348 | if (i < GIC_NUM_INTRS) { | ||
349 | gic_irq_flags[i] = 0; | ||
350 | gic_shared_intr_map[i].num_shared_intr = 0; | ||
351 | gic_shared_intr_map[i].local_intr_mask = 0; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * In EIC mode, the HW_INT# is offset by (2-1). Need to subtract | ||
357 | * one because the GIC will add one (since 0=no intr). | ||
358 | */ | ||
359 | if (cpu_has_veic) | ||
360 | pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); | ||
361 | |||
362 | /* Setup specifics */ | ||
363 | for (i = 0; i < mapsize; i++) { | ||
364 | cpu = intrmap[i].cpunum; | ||
365 | if (cpu == GIC_UNUSED) | ||
366 | continue; | ||
367 | gic_setup_intr(i, | ||
368 | intrmap[i].cpunum, | ||
369 | intrmap[i].pin + pin_offset, | ||
370 | intrmap[i].polarity, | ||
371 | intrmap[i].trigtype, | ||
372 | intrmap[i].flags); | ||
373 | } | ||
374 | |||
375 | vpe_local_setup(numvpes); | ||
376 | } | ||
377 | |||
378 | void __init gic_init(unsigned long gic_base_addr, | ||
379 | unsigned long gic_addrspace_size, | ||
380 | struct gic_intr_map *intr_map, unsigned int intr_map_size, | ||
381 | unsigned int irqbase) | ||
382 | { | ||
383 | unsigned int gicconfig; | ||
384 | int numvpes, numintrs; | ||
385 | |||
386 | _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, | ||
387 | gic_addrspace_size); | ||
388 | gic_irq_base = irqbase; | ||
389 | |||
390 | GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); | ||
391 | numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> | ||
392 | GIC_SH_CONFIG_NUMINTRS_SHF; | ||
393 | numintrs = ((numintrs + 1) * 8); | ||
394 | |||
395 | numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> | ||
396 | GIC_SH_CONFIG_NUMVPES_SHF; | ||
397 | numvpes = numvpes + 1; | ||
398 | |||
399 | gic_basic_init(numintrs, numvpes, intr_map, intr_map_size); | ||
400 | |||
401 | gic_platform_init(numintrs, &gic_irq_controller); | ||
402 | } | ||
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index e498f2b3646a..590c2c980fd3 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <asm/irq_cpu.h> | 36 | #include <asm/irq_cpu.h> |
37 | #include <asm/mipsregs.h> | 37 | #include <asm/mipsregs.h> |
38 | #include <asm/mipsmtregs.h> | 38 | #include <asm/mipsmtregs.h> |
39 | #include <asm/setup.h> | ||
39 | 40 | ||
40 | static inline void unmask_mips_irq(struct irq_data *d) | 41 | static inline void unmask_mips_irq(struct irq_data *d) |
41 | { | 42 | { |
@@ -94,28 +95,24 @@ static struct irq_chip mips_mt_cpu_irq_controller = { | |||
94 | .irq_eoi = unmask_mips_irq, | 95 | .irq_eoi = unmask_mips_irq, |
95 | }; | 96 | }; |
96 | 97 | ||
97 | void __init mips_cpu_irq_init(void) | 98 | asmlinkage void __weak plat_irq_dispatch(void) |
98 | { | 99 | { |
99 | int irq_base = MIPS_CPU_IRQ_BASE; | 100 | unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM; |
100 | int i; | 101 | int irq; |
101 | 102 | ||
102 | /* Mask interrupts. */ | 103 | if (!pending) { |
103 | clear_c0_status(ST0_IM); | 104 | spurious_interrupt(); |
104 | clear_c0_cause(CAUSEF_IP); | 105 | return; |
105 | 106 | } | |
106 | /* Software interrupts are used for MT/CMT IPI */ | ||
107 | for (i = irq_base; i < irq_base + 2; i++) | ||
108 | irq_set_chip_and_handler(i, cpu_has_mipsmt ? | ||
109 | &mips_mt_cpu_irq_controller : | ||
110 | &mips_cpu_irq_controller, | ||
111 | handle_percpu_irq); | ||
112 | 107 | ||
113 | for (i = irq_base + 2; i < irq_base + 8; i++) | 108 | pending >>= CAUSEB_IP; |
114 | irq_set_chip_and_handler(i, &mips_cpu_irq_controller, | 109 | while (pending) { |
115 | handle_percpu_irq); | 110 | irq = fls(pending) - 1; |
111 | do_IRQ(MIPS_CPU_IRQ_BASE + irq); | ||
112 | pending &= ~BIT(irq); | ||
113 | } | ||
116 | } | 114 | } |
117 | 115 | ||
118 | #ifdef CONFIG_IRQ_DOMAIN | ||
119 | static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq, | 116 | static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq, |
120 | irq_hw_number_t hw) | 117 | irq_hw_number_t hw) |
121 | { | 118 | { |
@@ -128,6 +125,9 @@ static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq, | |||
128 | chip = &mips_cpu_irq_controller; | 125 | chip = &mips_cpu_irq_controller; |
129 | } | 126 | } |
130 | 127 | ||
128 | if (cpu_has_vint) | ||
129 | set_vi_handler(hw, plat_irq_dispatch); | ||
130 | |||
131 | irq_set_chip_and_handler(irq, chip, handle_percpu_irq); | 131 | irq_set_chip_and_handler(irq, chip, handle_percpu_irq); |
132 | 132 | ||
133 | return 0; | 133 | return 0; |
@@ -138,8 +138,7 @@ static const struct irq_domain_ops mips_cpu_intc_irq_domain_ops = { | |||
138 | .xlate = irq_domain_xlate_onecell, | 138 | .xlate = irq_domain_xlate_onecell, |
139 | }; | 139 | }; |
140 | 140 | ||
141 | int __init mips_cpu_intc_init(struct device_node *of_node, | 141 | static void __init __mips_cpu_irq_init(struct device_node *of_node) |
142 | struct device_node *parent) | ||
143 | { | 142 | { |
144 | struct irq_domain *domain; | 143 | struct irq_domain *domain; |
145 | 144 | ||
@@ -151,7 +150,16 @@ int __init mips_cpu_intc_init(struct device_node *of_node, | |||
151 | &mips_cpu_intc_irq_domain_ops, NULL); | 150 | &mips_cpu_intc_irq_domain_ops, NULL); |
152 | if (!domain) | 151 | if (!domain) |
153 | panic("Failed to add irqdomain for MIPS CPU"); | 152 | panic("Failed to add irqdomain for MIPS CPU"); |
153 | } | ||
154 | 154 | ||
155 | void __init mips_cpu_irq_init(void) | ||
156 | { | ||
157 | __mips_cpu_irq_init(NULL); | ||
158 | } | ||
159 | |||
160 | int __init mips_cpu_irq_of_init(struct device_node *of_node, | ||
161 | struct device_node *parent) | ||
162 | { | ||
163 | __mips_cpu_irq_init(of_node); | ||
155 | return 0; | 164 | return 0; |
156 | } | 165 | } |
157 | #endif /* CONFIG_IRQ_DOMAIN */ | ||
diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index f76f7a08412d..85bbe9b96759 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c | |||
@@ -16,7 +16,7 @@ | |||
16 | void __iomem *mips_cm_base; | 16 | void __iomem *mips_cm_base; |
17 | void __iomem *mips_cm_l2sync_base; | 17 | void __iomem *mips_cm_l2sync_base; |
18 | 18 | ||
19 | phys_t __mips_cm_phys_base(void) | 19 | phys_addr_t __mips_cm_phys_base(void) |
20 | { | 20 | { |
21 | u32 config3 = read_c0_config3(); | 21 | u32 config3 = read_c0_config3(); |
22 | u32 cmgcr; | 22 | u32 cmgcr; |
@@ -30,10 +30,10 @@ phys_t __mips_cm_phys_base(void) | |||
30 | return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32); | 30 | return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32); |
31 | } | 31 | } |
32 | 32 | ||
33 | phys_t mips_cm_phys_base(void) | 33 | phys_addr_t mips_cm_phys_base(void) |
34 | __attribute__((weak, alias("__mips_cm_phys_base"))); | 34 | __attribute__((weak, alias("__mips_cm_phys_base"))); |
35 | 35 | ||
36 | phys_t __mips_cm_l2sync_phys_base(void) | 36 | phys_addr_t __mips_cm_l2sync_phys_base(void) |
37 | { | 37 | { |
38 | u32 base_reg; | 38 | u32 base_reg; |
39 | 39 | ||
@@ -49,13 +49,13 @@ phys_t __mips_cm_l2sync_phys_base(void) | |||
49 | return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; | 49 | return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; |
50 | } | 50 | } |
51 | 51 | ||
52 | phys_t mips_cm_l2sync_phys_base(void) | 52 | phys_addr_t mips_cm_l2sync_phys_base(void) |
53 | __attribute__((weak, alias("__mips_cm_l2sync_phys_base"))); | 53 | __attribute__((weak, alias("__mips_cm_l2sync_phys_base"))); |
54 | 54 | ||
55 | static void mips_cm_probe_l2sync(void) | 55 | static void mips_cm_probe_l2sync(void) |
56 | { | 56 | { |
57 | unsigned major_rev; | 57 | unsigned major_rev; |
58 | phys_t addr; | 58 | phys_addr_t addr; |
59 | 59 | ||
60 | /* L2-only sync was introduced with CM major revision 6 */ | 60 | /* L2-only sync was introduced with CM major revision 6 */ |
61 | major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR_MSK) >> | 61 | major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR_MSK) >> |
@@ -78,7 +78,7 @@ static void mips_cm_probe_l2sync(void) | |||
78 | 78 | ||
79 | int mips_cm_probe(void) | 79 | int mips_cm_probe(void) |
80 | { | 80 | { |
81 | phys_t addr; | 81 | phys_addr_t addr; |
82 | u32 base_reg; | 82 | u32 base_reg; |
83 | 83 | ||
84 | addr = mips_cm_phys_base(); | 84 | addr = mips_cm_phys_base(); |
diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index ba473608a347..11964501c4b0 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c | |||
@@ -21,7 +21,7 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); | |||
21 | 21 | ||
22 | static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); | 22 | static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); |
23 | 23 | ||
24 | phys_t __weak mips_cpc_phys_base(void) | 24 | phys_addr_t __weak mips_cpc_phys_base(void) |
25 | { | 25 | { |
26 | u32 cpc_base; | 26 | u32 cpc_base; |
27 | 27 | ||
@@ -44,7 +44,7 @@ phys_t __weak mips_cpc_phys_base(void) | |||
44 | 44 | ||
45 | int mips_cpc_probe(void) | 45 | int mips_cpc_probe(void) |
46 | { | 46 | { |
47 | phys_t addr; | 47 | phys_addr_t addr; |
48 | unsigned cpu; | 48 | unsigned cpu; |
49 | 49 | ||
50 | for_each_possible_cpu(cpu) | 50 | for_each_possible_cpu(cpu) |
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 2607c3a4ff7e..17eaf0cf760c 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c | |||
@@ -24,9 +24,7 @@ extern long __strncpy_from_user_nocheck_asm(char *__to, | |||
24 | const char *__from, long __len); | 24 | const char *__from, long __len); |
25 | extern long __strncpy_from_user_asm(char *__to, const char *__from, | 25 | extern long __strncpy_from_user_asm(char *__to, const char *__from, |
26 | long __len); | 26 | long __len); |
27 | extern long __strlen_kernel_nocheck_asm(const char *s); | ||
28 | extern long __strlen_kernel_asm(const char *s); | 27 | extern long __strlen_kernel_asm(const char *s); |
29 | extern long __strlen_user_nocheck_asm(const char *s); | ||
30 | extern long __strlen_user_asm(const char *s); | 28 | extern long __strlen_user_asm(const char *s); |
31 | extern long __strnlen_kernel_nocheck_asm(const char *s); | 29 | extern long __strnlen_kernel_nocheck_asm(const char *s); |
32 | extern long __strnlen_kernel_asm(const char *s); | 30 | extern long __strnlen_kernel_asm(const char *s); |
@@ -62,9 +60,7 @@ EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm); | |||
62 | EXPORT_SYMBOL(__strncpy_from_kernel_asm); | 60 | EXPORT_SYMBOL(__strncpy_from_kernel_asm); |
63 | EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm); | 61 | EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm); |
64 | EXPORT_SYMBOL(__strncpy_from_user_asm); | 62 | EXPORT_SYMBOL(__strncpy_from_user_asm); |
65 | EXPORT_SYMBOL(__strlen_kernel_nocheck_asm); | ||
66 | EXPORT_SYMBOL(__strlen_kernel_asm); | 63 | EXPORT_SYMBOL(__strlen_kernel_asm); |
67 | EXPORT_SYMBOL(__strlen_user_nocheck_asm); | ||
68 | EXPORT_SYMBOL(__strlen_user_asm); | 64 | EXPORT_SYMBOL(__strlen_user_asm); |
69 | EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm); | 65 | EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm); |
70 | EXPORT_SYMBOL(__strnlen_kernel_asm); | 66 | EXPORT_SYMBOL(__strnlen_kernel_asm); |
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index a8f9cdc6f8b0..9466184d0039 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c | |||
@@ -561,8 +561,8 @@ static int mipspmu_get_irq(void) | |||
561 | IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_THREAD, | 561 | IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_THREAD, |
562 | "mips_perf_pmu", NULL); | 562 | "mips_perf_pmu", NULL); |
563 | if (err) { | 563 | if (err) { |
564 | pr_warning("Unable to request IRQ%d for MIPS " | 564 | pr_warn("Unable to request IRQ%d for MIPS performance counters!\n", |
565 | "performance counters!\n", mipspmu.irq); | 565 | mipspmu.irq); |
566 | } | 566 | } |
567 | } else if (cp0_perfcount_irq < 0) { | 567 | } else if (cp0_perfcount_irq < 0) { |
568 | /* | 568 | /* |
@@ -572,8 +572,7 @@ static int mipspmu_get_irq(void) | |||
572 | perf_irq = mipsxx_pmu_handle_shared_irq; | 572 | perf_irq = mipsxx_pmu_handle_shared_irq; |
573 | err = 0; | 573 | err = 0; |
574 | } else { | 574 | } else { |
575 | pr_warning("The platform hasn't properly defined its " | 575 | pr_warn("The platform hasn't properly defined its interrupt controller\n"); |
576 | "interrupt controller.\n"); | ||
577 | err = -ENOENT; | 576 | err = -ENOENT; |
578 | } | 577 | } |
579 | 578 | ||
@@ -1614,22 +1613,13 @@ init_hw_perf_events(void) | |||
1614 | counters = counters_total_to_per_cpu(counters); | 1613 | counters = counters_total_to_per_cpu(counters); |
1615 | #endif | 1614 | #endif |
1616 | 1615 | ||
1617 | #ifdef MSC01E_INT_BASE | 1616 | if (get_c0_perfcount_int) |
1618 | if (cpu_has_veic) { | 1617 | irq = get_c0_perfcount_int(); |
1619 | /* | 1618 | else if ((cp0_perfcount_irq >= 0) && |
1620 | * Using platform specific interrupt controller defines. | 1619 | (cp0_compare_irq != cp0_perfcount_irq)) |
1621 | */ | 1620 | irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; |
1622 | irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; | 1621 | else |
1623 | } else { | 1622 | irq = -1; |
1624 | #endif | ||
1625 | if ((cp0_perfcount_irq >= 0) && | ||
1626 | (cp0_compare_irq != cp0_perfcount_irq)) | ||
1627 | irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; | ||
1628 | else | ||
1629 | irq = -1; | ||
1630 | #ifdef MSC01E_INT_BASE | ||
1631 | } | ||
1632 | #endif | ||
1633 | 1623 | ||
1634 | mipspmu.map_raw_event = mipsxx_pmu_map_raw_event; | 1624 | mipspmu.map_raw_event = mipsxx_pmu_map_raw_event; |
1635 | 1625 | ||
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 636b0745d7c7..eb76434828e8 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <asm/isadep.h> | 42 | #include <asm/isadep.h> |
43 | #include <asm/inst.h> | 43 | #include <asm/inst.h> |
44 | #include <asm/stacktrace.h> | 44 | #include <asm/stacktrace.h> |
45 | #include <asm/irq_regs.h> | ||
45 | 46 | ||
46 | #ifdef CONFIG_HOTPLUG_CPU | 47 | #ifdef CONFIG_HOTPLUG_CPU |
47 | void arch_cpu_idle_dead(void) | 48 | void arch_cpu_idle_dead(void) |
@@ -187,21 +188,21 @@ static inline int is_ra_save_ins(union mips_instruction *ip) | |||
187 | */ | 188 | */ |
188 | if (mm_insn_16bit(ip->halfword[0])) { | 189 | if (mm_insn_16bit(ip->halfword[0])) { |
189 | mmi.word = (ip->halfword[0] << 16); | 190 | mmi.word = (ip->halfword[0] << 16); |
190 | return ((mmi.mm16_r5_format.opcode == mm_swsp16_op && | 191 | return (mmi.mm16_r5_format.opcode == mm_swsp16_op && |
191 | mmi.mm16_r5_format.rt == 31) || | 192 | mmi.mm16_r5_format.rt == 31) || |
192 | (mmi.mm16_m_format.opcode == mm_pool16c_op && | 193 | (mmi.mm16_m_format.opcode == mm_pool16c_op && |
193 | mmi.mm16_m_format.func == mm_swm16_op)); | 194 | mmi.mm16_m_format.func == mm_swm16_op); |
194 | } | 195 | } |
195 | else { | 196 | else { |
196 | mmi.halfword[0] = ip->halfword[1]; | 197 | mmi.halfword[0] = ip->halfword[1]; |
197 | mmi.halfword[1] = ip->halfword[0]; | 198 | mmi.halfword[1] = ip->halfword[0]; |
198 | return ((mmi.mm_m_format.opcode == mm_pool32b_op && | 199 | return (mmi.mm_m_format.opcode == mm_pool32b_op && |
199 | mmi.mm_m_format.rd > 9 && | 200 | mmi.mm_m_format.rd > 9 && |
200 | mmi.mm_m_format.base == 29 && | 201 | mmi.mm_m_format.base == 29 && |
201 | mmi.mm_m_format.func == mm_swm32_func) || | 202 | mmi.mm_m_format.func == mm_swm32_func) || |
202 | (mmi.i_format.opcode == mm_sw32_op && | 203 | (mmi.i_format.opcode == mm_sw32_op && |
203 | mmi.i_format.rs == 29 && | 204 | mmi.i_format.rs == 29 && |
204 | mmi.i_format.rt == 31)); | 205 | mmi.i_format.rt == 31); |
205 | } | 206 | } |
206 | #else | 207 | #else |
207 | /* sw / sd $ra, offset($sp) */ | 208 | /* sw / sd $ra, offset($sp) */ |
@@ -233,7 +234,7 @@ static inline int is_jump_ins(union mips_instruction *ip) | |||
233 | if (ip->r_format.opcode != mm_pool32a_op || | 234 | if (ip->r_format.opcode != mm_pool32a_op || |
234 | ip->r_format.func != mm_pool32axf_op) | 235 | ip->r_format.func != mm_pool32axf_op) |
235 | return 0; | 236 | return 0; |
236 | return (((ip->u_format.uimmediate >> 6) & mm_jalr_op) == mm_jalr_op); | 237 | return ((ip->u_format.uimmediate >> 6) & mm_jalr_op) == mm_jalr_op; |
237 | #else | 238 | #else |
238 | if (ip->j_format.opcode == j_op) | 239 | if (ip->j_format.opcode == j_op) |
239 | return 1; | 240 | return 1; |
@@ -260,13 +261,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip) | |||
260 | union mips_instruction mmi; | 261 | union mips_instruction mmi; |
261 | 262 | ||
262 | mmi.word = (ip->halfword[0] << 16); | 263 | mmi.word = (ip->halfword[0] << 16); |
263 | return ((mmi.mm16_r3_format.opcode == mm_pool16d_op && | 264 | return (mmi.mm16_r3_format.opcode == mm_pool16d_op && |
264 | mmi.mm16_r3_format.simmediate && mm_addiusp_func) || | 265 | mmi.mm16_r3_format.simmediate && mm_addiusp_func) || |
265 | (mmi.mm16_r5_format.opcode == mm_pool16d_op && | 266 | (mmi.mm16_r5_format.opcode == mm_pool16d_op && |
266 | mmi.mm16_r5_format.rt == 29)); | 267 | mmi.mm16_r5_format.rt == 29); |
267 | } | 268 | } |
268 | return (ip->mm_i_format.opcode == mm_addiu32_op && | 269 | return ip->mm_i_format.opcode == mm_addiu32_op && |
269 | ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29); | 270 | ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29; |
270 | #else | 271 | #else |
271 | /* addiu/daddiu sp,sp,-imm */ | 272 | /* addiu/daddiu sp,sp,-imm */ |
272 | if (ip->i_format.rs != 29 || ip->i_format.rt != 29) | 273 | if (ip->i_format.rs != 29 || ip->i_format.rt != 29) |
@@ -532,3 +533,20 @@ unsigned long arch_align_stack(unsigned long sp) | |||
532 | 533 | ||
533 | return sp & ALMASK; | 534 | return sp & ALMASK; |
534 | } | 535 | } |
536 | |||
537 | static void arch_dump_stack(void *info) | ||
538 | { | ||
539 | struct pt_regs *regs; | ||
540 | |||
541 | regs = get_irq_regs(); | ||
542 | |||
543 | if (regs) | ||
544 | show_regs(regs); | ||
545 | |||
546 | dump_stack(); | ||
547 | } | ||
548 | |||
549 | void arch_trigger_all_cpu_backtrace(bool include_self) | ||
550 | { | ||
551 | smp_call_function(arch_dump_stack, NULL, 1); | ||
552 | } | ||
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 5d39bb85bf35..452d4350ce42 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/debugfs.h> | 16 | #include <linux/debugfs.h> |
17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
18 | #include <linux/of_fdt.h> | 18 | #include <linux/of_fdt.h> |
19 | #include <linux/of_platform.h> | ||
19 | 20 | ||
20 | #include <asm/page.h> | 21 | #include <asm/page.h> |
21 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
@@ -54,4 +55,21 @@ void __init __dt_setup_arch(void *bph) | |||
54 | 55 | ||
55 | mips_set_machine_name(of_flat_dt_get_machine_name()); | 56 | mips_set_machine_name(of_flat_dt_get_machine_name()); |
56 | } | 57 | } |
58 | |||
59 | int __init __dt_register_buses(const char *bus0, const char *bus1) | ||
60 | { | ||
61 | static struct of_device_id of_ids[3]; | ||
62 | |||
63 | if (!of_have_populated_dt()) | ||
64 | panic("device tree not present"); | ||
65 | |||
66 | strlcpy(of_ids[0].compatible, bus0, sizeof(of_ids[0].compatible)); | ||
67 | strlcpy(of_ids[1].compatible, bus1, sizeof(of_ids[1].compatible)); | ||
68 | |||
69 | if (of_platform_populate(NULL, of_ids, NULL, NULL)) | ||
70 | panic("failed to populate DT"); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
57 | #endif | 75 | #endif |
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f3b635f86c39..058929041368 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
@@ -82,14 +82,14 @@ static struct resource data_resource = { .name = "Kernel data", }; | |||
82 | 82 | ||
83 | static void *detect_magic __initdata = detect_memory_region; | 83 | static void *detect_magic __initdata = detect_memory_region; |
84 | 84 | ||
85 | void __init add_memory_region(phys_t start, phys_t size, long type) | 85 | void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type) |
86 | { | 86 | { |
87 | int x = boot_mem_map.nr_map; | 87 | int x = boot_mem_map.nr_map; |
88 | int i; | 88 | int i; |
89 | 89 | ||
90 | /* Sanity check */ | 90 | /* Sanity check */ |
91 | if (start + size < start) { | 91 | if (start + size < start) { |
92 | pr_warning("Trying to add an invalid memory region, skipped\n"); | 92 | pr_warn("Trying to add an invalid memory region, skipped\n"); |
93 | return; | 93 | return; |
94 | } | 94 | } |
95 | 95 | ||
@@ -127,10 +127,10 @@ void __init add_memory_region(phys_t start, phys_t size, long type) | |||
127 | boot_mem_map.nr_map++; | 127 | boot_mem_map.nr_map++; |
128 | } | 128 | } |
129 | 129 | ||
130 | void __init detect_memory_region(phys_t start, phys_t sz_min, phys_t sz_max) | 130 | void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max) |
131 | { | 131 | { |
132 | void *dm = &detect_magic; | 132 | void *dm = &detect_magic; |
133 | phys_t size; | 133 | phys_addr_t size; |
134 | 134 | ||
135 | for (size = sz_min; size < sz_max; size <<= 1) { | 135 | for (size = sz_min; size < sz_max; size <<= 1) { |
136 | if (!memcmp(dm, dm + size, sizeof(detect_magic))) | 136 | if (!memcmp(dm, dm + size, sizeof(detect_magic))) |
@@ -493,7 +493,7 @@ static int usermem __initdata; | |||
493 | 493 | ||
494 | static int __init early_parse_mem(char *p) | 494 | static int __init early_parse_mem(char *p) |
495 | { | 495 | { |
496 | phys_t start, size; | 496 | phys_addr_t start, size; |
497 | 497 | ||
498 | /* | 498 | /* |
499 | * If a user specifies memory size, we | 499 | * If a user specifies memory size, we |
@@ -545,9 +545,9 @@ static int __init early_parse_elfcorehdr(char *p) | |||
545 | early_param("elfcorehdr", early_parse_elfcorehdr); | 545 | early_param("elfcorehdr", early_parse_elfcorehdr); |
546 | #endif | 546 | #endif |
547 | 547 | ||
548 | static void __init arch_mem_addpart(phys_t mem, phys_t end, int type) | 548 | static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type) |
549 | { | 549 | { |
550 | phys_t size; | 550 | phys_addr_t size; |
551 | int i; | 551 | int i; |
552 | 552 | ||
553 | size = end - mem; | 553 | size = end - mem; |
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 16f1e4f2bf3c..545bf11bd2ed 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
@@ -530,7 +530,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) | |||
530 | struct mips_abi *abi = current->thread.abi; | 530 | struct mips_abi *abi = current->thread.abi; |
531 | #ifdef CONFIG_CPU_MICROMIPS | 531 | #ifdef CONFIG_CPU_MICROMIPS |
532 | void *vdso; | 532 | void *vdso; |
533 | unsigned int tmp = (unsigned int)current->mm->context.vdso; | 533 | unsigned long tmp = (unsigned long)current->mm->context.vdso; |
534 | 534 | ||
535 | set_isa16_mode(tmp); | 535 | set_isa16_mode(tmp); |
536 | vdso = (void *)tmp; | 536 | vdso = (void *)tmp; |
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 06bb5ed6d80a..b8bd9340c9c7 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <asm/bmips.h> | 35 | #include <asm/bmips.h> |
36 | #include <asm/traps.h> | 36 | #include <asm/traps.h> |
37 | #include <asm/barrier.h> | 37 | #include <asm/barrier.h> |
38 | #include <asm/cpu-features.h> | ||
38 | 39 | ||
39 | static int __maybe_unused max_cpus = 1; | 40 | static int __maybe_unused max_cpus = 1; |
40 | 41 | ||
@@ -42,6 +43,12 @@ static int __maybe_unused max_cpus = 1; | |||
42 | int bmips_smp_enabled = 1; | 43 | int bmips_smp_enabled = 1; |
43 | int bmips_cpu_offset; | 44 | int bmips_cpu_offset; |
44 | cpumask_t bmips_booted_mask; | 45 | cpumask_t bmips_booted_mask; |
46 | unsigned long bmips_tp1_irqs = IE_IRQ1; | ||
47 | |||
48 | #define RESET_FROM_KSEG0 0x80080800 | ||
49 | #define RESET_FROM_KSEG1 0xa0080800 | ||
50 | |||
51 | static void bmips_set_reset_vec(int cpu, u32 val); | ||
45 | 52 | ||
46 | #ifdef CONFIG_SMP | 53 | #ifdef CONFIG_SMP |
47 | 54 | ||
@@ -194,6 +201,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) | |||
194 | pr_info("SMP: Booting CPU%d...\n", cpu); | 201 | pr_info("SMP: Booting CPU%d...\n", cpu); |
195 | 202 | ||
196 | if (cpumask_test_cpu(cpu, &bmips_booted_mask)) { | 203 | if (cpumask_test_cpu(cpu, &bmips_booted_mask)) { |
204 | /* kseg1 might not exist if this CPU enabled XKS01 */ | ||
205 | bmips_set_reset_vec(cpu, RESET_FROM_KSEG0); | ||
206 | |||
197 | switch (current_cpu_type()) { | 207 | switch (current_cpu_type()) { |
198 | case CPU_BMIPS4350: | 208 | case CPU_BMIPS4350: |
199 | case CPU_BMIPS4380: | 209 | case CPU_BMIPS4380: |
@@ -203,8 +213,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) | |||
203 | bmips5000_send_ipi_single(cpu, 0); | 213 | bmips5000_send_ipi_single(cpu, 0); |
204 | break; | 214 | break; |
205 | } | 215 | } |
206 | } | 216 | } else { |
207 | else { | 217 | bmips_set_reset_vec(cpu, RESET_FROM_KSEG1); |
218 | |||
208 | switch (current_cpu_type()) { | 219 | switch (current_cpu_type()) { |
209 | case CPU_BMIPS4350: | 220 | case CPU_BMIPS4350: |
210 | case CPU_BMIPS4380: | 221 | case CPU_BMIPS4380: |
@@ -213,17 +224,7 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) | |||
213 | set_c0_brcm_cmt_ctrl(0x01); | 224 | set_c0_brcm_cmt_ctrl(0x01); |
214 | break; | 225 | break; |
215 | case CPU_BMIPS5000: | 226 | case CPU_BMIPS5000: |
216 | if (cpu & 0x01) | 227 | write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); |
217 | write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); | ||
218 | else { | ||
219 | /* | ||
220 | * core N thread 0 was already booted; just | ||
221 | * pulse the NMI line | ||
222 | */ | ||
223 | bmips_write_zscm_reg(0x210, 0xc0000000); | ||
224 | udelay(10); | ||
225 | bmips_write_zscm_reg(0x210, 0x00); | ||
226 | } | ||
227 | break; | 228 | break; |
228 | } | 229 | } |
229 | cpumask_set_cpu(cpu, &bmips_booted_mask); | 230 | cpumask_set_cpu(cpu, &bmips_booted_mask); |
@@ -235,31 +236,12 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) | |||
235 | */ | 236 | */ |
236 | static void bmips_init_secondary(void) | 237 | static void bmips_init_secondary(void) |
237 | { | 238 | { |
238 | /* move NMI vector to kseg0, in case XKS01 is enabled */ | ||
239 | |||
240 | void __iomem *cbr; | ||
241 | unsigned long old_vec; | ||
242 | unsigned long relo_vector; | ||
243 | int boot_cpu; | ||
244 | |||
245 | switch (current_cpu_type()) { | 239 | switch (current_cpu_type()) { |
246 | case CPU_BMIPS4350: | 240 | case CPU_BMIPS4350: |
247 | case CPU_BMIPS4380: | 241 | case CPU_BMIPS4380: |
248 | cbr = BMIPS_GET_CBR(); | ||
249 | |||
250 | boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31)); | ||
251 | relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 : | ||
252 | BMIPS_RELO_VECTOR_CONTROL_1; | ||
253 | |||
254 | old_vec = __raw_readl(cbr + relo_vector); | ||
255 | __raw_writel(old_vec & ~0x20000000, cbr + relo_vector); | ||
256 | |||
257 | clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); | 242 | clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); |
258 | break; | 243 | break; |
259 | case CPU_BMIPS5000: | 244 | case CPU_BMIPS5000: |
260 | write_c0_brcm_bootvec(read_c0_brcm_bootvec() & | ||
261 | (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000)); | ||
262 | |||
263 | write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); | 245 | write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); |
264 | break; | 246 | break; |
265 | } | 247 | } |
@@ -276,7 +258,7 @@ static void bmips_smp_finish(void) | |||
276 | write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); | 258 | write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); |
277 | 259 | ||
278 | irq_enable_hazard(); | 260 | irq_enable_hazard(); |
279 | set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE); | 261 | set_c0_status(IE_SW0 | IE_SW1 | bmips_tp1_irqs | IE_IRQ5 | ST0_IE); |
280 | irq_enable_hazard(); | 262 | irq_enable_hazard(); |
281 | } | 263 | } |
282 | 264 | ||
@@ -381,6 +363,7 @@ static int bmips_cpu_disable(void) | |||
381 | 363 | ||
382 | set_cpu_online(cpu, false); | 364 | set_cpu_online(cpu, false); |
383 | cpu_clear(cpu, cpu_callin_map); | 365 | cpu_clear(cpu, cpu_callin_map); |
366 | clear_c0_status(IE_IRQ5); | ||
384 | 367 | ||
385 | local_flush_tlb_all(); | 368 | local_flush_tlb_all(); |
386 | local_flush_icache_range(0, ~0); | 369 | local_flush_icache_range(0, ~0); |
@@ -405,7 +388,8 @@ void __ref play_dead(void) | |||
405 | * IRQ handlers; this clears ST0_IE and returns immediately. | 388 | * IRQ handlers; this clears ST0_IE and returns immediately. |
406 | */ | 389 | */ |
407 | clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1); | 390 | clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1); |
408 | change_c0_status(IE_IRQ5 | IE_IRQ1 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV, | 391 | change_c0_status( |
392 | IE_IRQ5 | bmips_tp1_irqs | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV, | ||
409 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV); | 393 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV); |
410 | irq_disable_hazard(); | 394 | irq_disable_hazard(); |
411 | 395 | ||
@@ -473,10 +457,61 @@ static inline void bmips_nmi_handler_setup(void) | |||
473 | &bmips_smp_int_vec_end); | 457 | &bmips_smp_int_vec_end); |
474 | } | 458 | } |
475 | 459 | ||
460 | struct reset_vec_info { | ||
461 | int cpu; | ||
462 | u32 val; | ||
463 | }; | ||
464 | |||
465 | static void bmips_set_reset_vec_remote(void *vinfo) | ||
466 | { | ||
467 | struct reset_vec_info *info = vinfo; | ||
468 | int shift = info->cpu & 0x01 ? 16 : 0; | ||
469 | u32 mask = ~(0xffff << shift), val = info->val >> 16; | ||
470 | |||
471 | preempt_disable(); | ||
472 | if (smp_processor_id() > 0) { | ||
473 | smp_call_function_single(0, &bmips_set_reset_vec_remote, | ||
474 | info, 1); | ||
475 | } else { | ||
476 | if (info->cpu & 0x02) { | ||
477 | /* BMIPS5200 "should" use mask/shift, but it's buggy */ | ||
478 | bmips_write_zscm_reg(0xa0, (val << 16) | val); | ||
479 | bmips_read_zscm_reg(0xa0); | ||
480 | } else { | ||
481 | write_c0_brcm_bootvec((read_c0_brcm_bootvec() & mask) | | ||
482 | (val << shift)); | ||
483 | } | ||
484 | } | ||
485 | preempt_enable(); | ||
486 | } | ||
487 | |||
488 | static void bmips_set_reset_vec(int cpu, u32 val) | ||
489 | { | ||
490 | struct reset_vec_info info; | ||
491 | |||
492 | if (current_cpu_type() == CPU_BMIPS5000) { | ||
493 | /* this needs to run from CPU0 (which is always online) */ | ||
494 | info.cpu = cpu; | ||
495 | info.val = val; | ||
496 | bmips_set_reset_vec_remote(&info); | ||
497 | } else { | ||
498 | void __iomem *cbr = BMIPS_GET_CBR(); | ||
499 | |||
500 | if (cpu == 0) | ||
501 | __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0); | ||
502 | else { | ||
503 | if (current_cpu_type() != CPU_BMIPS4380) | ||
504 | return; | ||
505 | __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_1); | ||
506 | } | ||
507 | } | ||
508 | __sync(); | ||
509 | back_to_back_c0_hazard(); | ||
510 | } | ||
511 | |||
476 | void bmips_ebase_setup(void) | 512 | void bmips_ebase_setup(void) |
477 | { | 513 | { |
478 | unsigned long new_ebase = ebase; | 514 | unsigned long new_ebase = ebase; |
479 | void __iomem __maybe_unused *cbr; | ||
480 | 515 | ||
481 | BUG_ON(ebase != CKSEG0); | 516 | BUG_ON(ebase != CKSEG0); |
482 | 517 | ||
@@ -496,15 +531,14 @@ void bmips_ebase_setup(void) | |||
496 | &bmips_smp_int_vec, 0x80); | 531 | &bmips_smp_int_vec, 0x80); |
497 | __sync(); | 532 | __sync(); |
498 | return; | 533 | return; |
534 | case CPU_BMIPS3300: | ||
499 | case CPU_BMIPS4380: | 535 | case CPU_BMIPS4380: |
500 | /* | 536 | /* |
501 | * 0x8000_0000: reset/NMI (initially in kseg1) | 537 | * 0x8000_0000: reset/NMI (initially in kseg1) |
502 | * 0x8000_0400: normal vectors | 538 | * 0x8000_0400: normal vectors |
503 | */ | 539 | */ |
504 | new_ebase = 0x80000400; | 540 | new_ebase = 0x80000400; |
505 | cbr = BMIPS_GET_CBR(); | 541 | bmips_set_reset_vec(0, RESET_FROM_KSEG0); |
506 | __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0); | ||
507 | __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1); | ||
508 | break; | 542 | break; |
509 | case CPU_BMIPS5000: | 543 | case CPU_BMIPS5000: |
510 | /* | 544 | /* |
@@ -512,10 +546,8 @@ void bmips_ebase_setup(void) | |||
512 | * 0x8000_1000: normal vectors | 546 | * 0x8000_1000: normal vectors |
513 | */ | 547 | */ |
514 | new_ebase = 0x80001000; | 548 | new_ebase = 0x80001000; |
515 | write_c0_brcm_bootvec(0xa0088008); | 549 | bmips_set_reset_vec(0, RESET_FROM_KSEG0); |
516 | write_c0_ebase(new_ebase); | 550 | write_c0_ebase(new_ebase); |
517 | if (max_cpus > 2) | ||
518 | bmips_write_zscm_reg(0xa0, 0xa008a008); | ||
519 | break; | 551 | break; |
520 | default: | 552 | default: |
521 | return; | 553 | return; |
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c index fc8a51553426..1e0a93c5a3e7 100644 --- a/arch/mips/kernel/smp-cmp.c +++ b/arch/mips/kernel/smp-cmp.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/cpumask.h> | 24 | #include <linux/cpumask.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/compiler.h> | 26 | #include <linux/compiler.h> |
27 | #include <linux/irqchip/mips-gic.h> | ||
27 | 28 | ||
28 | #include <linux/atomic.h> | 29 | #include <linux/atomic.h> |
29 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
@@ -37,7 +38,6 @@ | |||
37 | #include <asm/mipsmtregs.h> | 38 | #include <asm/mipsmtregs.h> |
38 | #include <asm/mips_mt.h> | 39 | #include <asm/mips_mt.h> |
39 | #include <asm/amon.h> | 40 | #include <asm/amon.h> |
40 | #include <asm/gic.h> | ||
41 | 41 | ||
42 | static void cmp_init_secondary(void) | 42 | static void cmp_init_secondary(void) |
43 | { | 43 | { |
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index e6e16a1d4add..bed7590e475f 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c | |||
@@ -9,13 +9,13 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/io.h> | 11 | #include <linux/io.h> |
12 | #include <linux/irqchip/mips-gic.h> | ||
12 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
13 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
14 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
15 | #include <linux/types.h> | 16 | #include <linux/types.h> |
16 | 17 | ||
17 | #include <asm/bcache.h> | 18 | #include <asm/bcache.h> |
18 | #include <asm/gic.h> | ||
19 | #include <asm/mips-cm.h> | 19 | #include <asm/mips-cm.h> |
20 | #include <asm/mips-cpc.h> | 20 | #include <asm/mips-cpc.h> |
21 | #include <asm/mips_mt.h> | 21 | #include <asm/mips_mt.h> |
@@ -273,8 +273,8 @@ static void cps_init_secondary(void) | |||
273 | if (cpu_has_mipsmt) | 273 | if (cpu_has_mipsmt) |
274 | dmt(); | 274 | dmt(); |
275 | 275 | ||
276 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | | 276 | change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | |
277 | STATUSF_IP6 | STATUSF_IP7); | 277 | STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); |
278 | } | 278 | } |
279 | 279 | ||
280 | static void cps_smp_finish(void) | 280 | static void cps_smp_finish(void) |
diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c index 3b21a96d1ccb..5f0ab5bcd01e 100644 --- a/arch/mips/kernel/smp-gic.c +++ b/arch/mips/kernel/smp-gic.c | |||
@@ -12,9 +12,9 @@ | |||
12 | * option) any later version. | 12 | * option) any later version. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/irqchip/mips-gic.h> | ||
15 | #include <linux/printk.h> | 16 | #include <linux/printk.h> |
16 | 17 | ||
17 | #include <asm/gic.h> | ||
18 | #include <asm/mips-cpc.h> | 18 | #include <asm/mips-cpc.h> |
19 | #include <asm/smp-ops.h> | 19 | #include <asm/smp-ops.h> |
20 | 20 | ||
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 21f23add04f4..ad86951b73bd 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/cpumask.h> | 22 | #include <linux/cpumask.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/irqchip/mips-gic.h> | ||
24 | #include <linux/compiler.h> | 25 | #include <linux/compiler.h> |
25 | #include <linux/smp.h> | 26 | #include <linux/smp.h> |
26 | 27 | ||
@@ -34,7 +35,6 @@ | |||
34 | #include <asm/mipsregs.h> | 35 | #include <asm/mipsregs.h> |
35 | #include <asm/mipsmtregs.h> | 36 | #include <asm/mipsmtregs.h> |
36 | #include <asm/mips_mt.h> | 37 | #include <asm/mips_mt.h> |
37 | #include <asm/gic.h> | ||
38 | 38 | ||
39 | static void __init smvp_copy_vpe_config(void) | 39 | static void __init smvp_copy_vpe_config(void) |
40 | { | 40 | { |
@@ -119,7 +119,7 @@ static void vsmp_send_ipi_single(int cpu, unsigned int action) | |||
119 | unsigned long flags; | 119 | unsigned long flags; |
120 | int vpflags; | 120 | int vpflags; |
121 | 121 | ||
122 | #ifdef CONFIG_IRQ_GIC | 122 | #ifdef CONFIG_MIPS_GIC |
123 | if (gic_present) { | 123 | if (gic_present) { |
124 | gic_send_ipi_single(cpu, action); | 124 | gic_send_ipi_single(cpu, action); |
125 | return; | 125 | return; |
@@ -158,7 +158,7 @@ static void vsmp_send_ipi_mask(const struct cpumask *mask, unsigned int action) | |||
158 | 158 | ||
159 | static void vsmp_init_secondary(void) | 159 | static void vsmp_init_secondary(void) |
160 | { | 160 | { |
161 | #ifdef CONFIG_IRQ_GIC | 161 | #ifdef CONFIG_MIPS_GIC |
162 | /* This is Malta specific: IPI,performance and timer interrupts */ | 162 | /* This is Malta specific: IPI,performance and timer interrupts */ |
163 | if (gic_present) | 163 | if (gic_present) |
164 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | | 164 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | |
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 4a4f9dda5658..604b558809c4 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c | |||
@@ -117,6 +117,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) | |||
117 | "2: sc %[tmp], (%[addr]) \n" | 117 | "2: sc %[tmp], (%[addr]) \n" |
118 | " beqzl %[tmp], 1b \n" | 118 | " beqzl %[tmp], 1b \n" |
119 | "3: \n" | 119 | "3: \n" |
120 | " .insn \n" | ||
120 | " .section .fixup,\"ax\" \n" | 121 | " .section .fixup,\"ax\" \n" |
121 | "4: li %[err], %[efault] \n" | 122 | "4: li %[err], %[efault] \n" |
122 | " j 3b \n" | 123 | " j 3b \n" |
@@ -142,6 +143,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) | |||
142 | "2: sc %[tmp], (%[addr]) \n" | 143 | "2: sc %[tmp], (%[addr]) \n" |
143 | " bnez %[tmp], 4f \n" | 144 | " bnez %[tmp], 4f \n" |
144 | "3: \n" | 145 | "3: \n" |
146 | " .insn \n" | ||
145 | " .subsection 2 \n" | 147 | " .subsection 2 \n" |
146 | "4: b 1b \n" | 148 | "4: b 1b \n" |
147 | " .previous \n" | 149 | " .previous \n" |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 22b19c275044..ad3d2031c327 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -724,6 +724,50 @@ int process_fpemu_return(int sig, void __user *fault_addr) | |||
724 | } | 724 | } |
725 | } | 725 | } |
726 | 726 | ||
727 | static int simulate_fp(struct pt_regs *regs, unsigned int opcode, | ||
728 | unsigned long old_epc, unsigned long old_ra) | ||
729 | { | ||
730 | union mips_instruction inst = { .word = opcode }; | ||
731 | void __user *fault_addr = NULL; | ||
732 | int sig; | ||
733 | |||
734 | /* If it's obviously not an FP instruction, skip it */ | ||
735 | switch (inst.i_format.opcode) { | ||
736 | case cop1_op: | ||
737 | case cop1x_op: | ||
738 | case lwc1_op: | ||
739 | case ldc1_op: | ||
740 | case swc1_op: | ||
741 | case sdc1_op: | ||
742 | break; | ||
743 | |||
744 | default: | ||
745 | return -1; | ||
746 | } | ||
747 | |||
748 | /* | ||
749 | * do_ri skipped over the instruction via compute_return_epc, undo | ||
750 | * that for the FPU emulator. | ||
751 | */ | ||
752 | regs->cp0_epc = old_epc; | ||
753 | regs->regs[31] = old_ra; | ||
754 | |||
755 | /* Save the FP context to struct thread_struct */ | ||
756 | lose_fpu(1); | ||
757 | |||
758 | /* Run the emulator */ | ||
759 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, | ||
760 | &fault_addr); | ||
761 | |||
762 | /* If something went wrong, signal */ | ||
763 | process_fpemu_return(sig, fault_addr); | ||
764 | |||
765 | /* Restore the hardware register state */ | ||
766 | own_fpu(1); | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
727 | /* | 771 | /* |
728 | * XXX Delayed fp exceptions when doing a lazy ctx switch XXX | 772 | * XXX Delayed fp exceptions when doing a lazy ctx switch XXX |
729 | */ | 773 | */ |
@@ -1016,6 +1060,9 @@ asmlinkage void do_ri(struct pt_regs *regs) | |||
1016 | 1060 | ||
1017 | if (status < 0) | 1061 | if (status < 0) |
1018 | status = simulate_sync(regs, opcode); | 1062 | status = simulate_sync(regs, opcode); |
1063 | |||
1064 | if (status < 0) | ||
1065 | status = simulate_fp(regs, opcode, old_epc, old31); | ||
1019 | } | 1066 | } |
1020 | 1067 | ||
1021 | if (status < 0) | 1068 | if (status < 0) |
@@ -1380,12 +1427,19 @@ asmlinkage void do_mcheck(struct pt_regs *regs) | |||
1380 | show_regs(regs); | 1427 | show_regs(regs); |
1381 | 1428 | ||
1382 | if (multi_match) { | 1429 | if (multi_match) { |
1383 | printk("Index : %0x\n", read_c0_index()); | 1430 | pr_err("Index : %0x\n", read_c0_index()); |
1384 | printk("Pagemask: %0x\n", read_c0_pagemask()); | 1431 | pr_err("Pagemask: %0x\n", read_c0_pagemask()); |
1385 | printk("EntryHi : %0*lx\n", field, read_c0_entryhi()); | 1432 | pr_err("EntryHi : %0*lx\n", field, read_c0_entryhi()); |
1386 | printk("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); | 1433 | pr_err("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); |
1387 | printk("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); | 1434 | pr_err("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); |
1388 | printk("\n"); | 1435 | pr_err("Wired : %0x\n", read_c0_wired()); |
1436 | pr_err("Pagegrain: %0x\n", read_c0_pagegrain()); | ||
1437 | if (cpu_has_htw) { | ||
1438 | pr_err("PWField : %0*lx\n", field, read_c0_pwfield()); | ||
1439 | pr_err("PWSize : %0*lx\n", field, read_c0_pwsize()); | ||
1440 | pr_err("PWCtl : %0x\n", read_c0_pwctl()); | ||
1441 | } | ||
1442 | pr_err("\n"); | ||
1389 | dump_tlb_all(); | 1443 | dump_tlb_all(); |
1390 | } | 1444 | } |
1391 | 1445 | ||
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index 0f1af58b036a..ed2a278722a9 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c | |||
@@ -16,9 +16,11 @@ | |||
16 | #include <linux/elf.h> | 16 | #include <linux/elf.h> |
17 | #include <linux/vmalloc.h> | 17 | #include <linux/vmalloc.h> |
18 | #include <linux/unistd.h> | 18 | #include <linux/unistd.h> |
19 | #include <linux/random.h> | ||
19 | 20 | ||
20 | #include <asm/vdso.h> | 21 | #include <asm/vdso.h> |
21 | #include <asm/uasm.h> | 22 | #include <asm/uasm.h> |
23 | #include <asm/processor.h> | ||
22 | 24 | ||
23 | /* | 25 | /* |
24 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... | 26 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... |
@@ -67,7 +69,18 @@ subsys_initcall(init_vdso); | |||
67 | 69 | ||
68 | static unsigned long vdso_addr(unsigned long start) | 70 | static unsigned long vdso_addr(unsigned long start) |
69 | { | 71 | { |
70 | return STACK_TOP; | 72 | unsigned long offset = 0UL; |
73 | |||
74 | if (current->flags & PF_RANDOMIZE) { | ||
75 | offset = get_random_int(); | ||
76 | offset <<= PAGE_SHIFT; | ||
77 | if (TASK_IS_32BIT_ADDR) | ||
78 | offset &= 0xfffffful; | ||
79 | else | ||
80 | offset &= 0xffffffful; | ||
81 | } | ||
82 | |||
83 | return STACK_TOP + offset; | ||
71 | } | 84 | } |
72 | 85 | ||
73 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | 86 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) |