diff options
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/module.c | 43 | ||||
-rw-r--r-- | arch/mips/kernel/smp.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/sync-r4k.c | 26 |
3 files changed, 47 insertions, 26 deletions
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index a5066b1c3de3..4f8c3cba8c0c 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c | |||
@@ -39,8 +39,6 @@ struct mips_hi16 { | |||
39 | Elf_Addr value; | 39 | Elf_Addr value; |
40 | }; | 40 | }; |
41 | 41 | ||
42 | static struct mips_hi16 *mips_hi16_list; | ||
43 | |||
44 | static LIST_HEAD(dbe_list); | 42 | static LIST_HEAD(dbe_list); |
45 | static DEFINE_SPINLOCK(dbe_lock); | 43 | static DEFINE_SPINLOCK(dbe_lock); |
46 | 44 | ||
@@ -128,8 +126,8 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v) | |||
128 | 126 | ||
129 | n->addr = (Elf_Addr *)location; | 127 | n->addr = (Elf_Addr *)location; |
130 | n->value = v; | 128 | n->value = v; |
131 | n->next = mips_hi16_list; | 129 | n->next = me->arch.r_mips_hi16_list; |
132 | mips_hi16_list = n; | 130 | me->arch.r_mips_hi16_list = n; |
133 | 131 | ||
134 | return 0; | 132 | return 0; |
135 | } | 133 | } |
@@ -142,18 +140,28 @@ static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v) | |||
142 | return 0; | 140 | return 0; |
143 | } | 141 | } |
144 | 142 | ||
143 | static void free_relocation_chain(struct mips_hi16 *l) | ||
144 | { | ||
145 | struct mips_hi16 *next; | ||
146 | |||
147 | while (l) { | ||
148 | next = l->next; | ||
149 | kfree(l); | ||
150 | l = next; | ||
151 | } | ||
152 | } | ||
153 | |||
145 | static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) | 154 | static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) |
146 | { | 155 | { |
147 | unsigned long insnlo = *location; | 156 | unsigned long insnlo = *location; |
157 | struct mips_hi16 *l; | ||
148 | Elf_Addr val, vallo; | 158 | Elf_Addr val, vallo; |
149 | 159 | ||
150 | /* Sign extend the addend we extract from the lo insn. */ | 160 | /* Sign extend the addend we extract from the lo insn. */ |
151 | vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; | 161 | vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; |
152 | 162 | ||
153 | if (mips_hi16_list != NULL) { | 163 | if (me->arch.r_mips_hi16_list != NULL) { |
154 | struct mips_hi16 *l; | 164 | l = me->arch.r_mips_hi16_list; |
155 | |||
156 | l = mips_hi16_list; | ||
157 | while (l != NULL) { | 165 | while (l != NULL) { |
158 | struct mips_hi16 *next; | 166 | struct mips_hi16 *next; |
159 | unsigned long insn; | 167 | unsigned long insn; |
@@ -188,7 +196,7 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) | |||
188 | l = next; | 196 | l = next; |
189 | } | 197 | } |
190 | 198 | ||
191 | mips_hi16_list = NULL; | 199 | me->arch.r_mips_hi16_list = NULL; |
192 | } | 200 | } |
193 | 201 | ||
194 | /* | 202 | /* |
@@ -201,6 +209,9 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) | |||
201 | return 0; | 209 | return 0; |
202 | 210 | ||
203 | out_danger: | 211 | out_danger: |
212 | free_relocation_chain(l); | ||
213 | me->arch.r_mips_hi16_list = NULL; | ||
214 | |||
204 | pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name); | 215 | pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name); |
205 | 216 | ||
206 | return -ENOEXEC; | 217 | return -ENOEXEC; |
@@ -273,6 +284,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, | |||
273 | pr_debug("Applying relocate section %u to %u\n", relsec, | 284 | pr_debug("Applying relocate section %u to %u\n", relsec, |
274 | sechdrs[relsec].sh_info); | 285 | sechdrs[relsec].sh_info); |
275 | 286 | ||
287 | me->arch.r_mips_hi16_list = NULL; | ||
276 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | 288 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { |
277 | /* This is where to make the change */ | 289 | /* This is where to make the change */ |
278 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | 290 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr |
@@ -296,6 +308,19 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, | |||
296 | return res; | 308 | return res; |
297 | } | 309 | } |
298 | 310 | ||
311 | /* | ||
312 | * Normally the hi16 list should be deallocated at this point. A | ||
313 | * malformed binary however could contain a series of R_MIPS_HI16 | ||
314 | * relocations not followed by a R_MIPS_LO16 relocation. In that | ||
315 | * case, free up the list and return an error. | ||
316 | */ | ||
317 | if (me->arch.r_mips_hi16_list) { | ||
318 | free_relocation_chain(me->arch.r_mips_hi16_list); | ||
319 | me->arch.r_mips_hi16_list = NULL; | ||
320 | |||
321 | return -ENOEXEC; | ||
322 | } | ||
323 | |||
299 | return 0; | 324 | return 0; |
300 | } | 325 | } |
301 | 326 | ||
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 31637d8c8738..9005bf9fb859 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c | |||
@@ -130,7 +130,7 @@ asmlinkage __cpuinit void start_secondary(void) | |||
130 | 130 | ||
131 | cpu_set(cpu, cpu_callin_map); | 131 | cpu_set(cpu, cpu_callin_map); |
132 | 132 | ||
133 | synchronise_count_slave(); | 133 | synchronise_count_slave(cpu); |
134 | 134 | ||
135 | /* | 135 | /* |
136 | * irq will be enabled in ->smp_finish(), enabling it too early | 136 | * irq will be enabled in ->smp_finish(), enabling it too early |
@@ -173,7 +173,6 @@ void smp_send_stop(void) | |||
173 | void __init smp_cpus_done(unsigned int max_cpus) | 173 | void __init smp_cpus_done(unsigned int max_cpus) |
174 | { | 174 | { |
175 | mp_ops->cpus_done(); | 175 | mp_ops->cpus_done(); |
176 | synchronise_count_master(); | ||
177 | } | 176 | } |
178 | 177 | ||
179 | /* called from main before smp_init() */ | 178 | /* called from main before smp_init() */ |
@@ -206,6 +205,7 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle) | |||
206 | while (!cpu_isset(cpu, cpu_callin_map)) | 205 | while (!cpu_isset(cpu, cpu_callin_map)) |
207 | udelay(100); | 206 | udelay(100); |
208 | 207 | ||
208 | synchronise_count_master(cpu); | ||
209 | return 0; | 209 | return 0; |
210 | } | 210 | } |
211 | 211 | ||
diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c index 842d55e411fd..7f1eca3858de 100644 --- a/arch/mips/kernel/sync-r4k.c +++ b/arch/mips/kernel/sync-r4k.c | |||
@@ -28,12 +28,11 @@ static atomic_t __cpuinitdata count_reference = ATOMIC_INIT(0); | |||
28 | #define COUNTON 100 | 28 | #define COUNTON 100 |
29 | #define NR_LOOPS 5 | 29 | #define NR_LOOPS 5 |
30 | 30 | ||
31 | void __cpuinit synchronise_count_master(void) | 31 | void __cpuinit synchronise_count_master(int cpu) |
32 | { | 32 | { |
33 | int i; | 33 | int i; |
34 | unsigned long flags; | 34 | unsigned long flags; |
35 | unsigned int initcount; | 35 | unsigned int initcount; |
36 | int nslaves; | ||
37 | 36 | ||
38 | #ifdef CONFIG_MIPS_MT_SMTC | 37 | #ifdef CONFIG_MIPS_MT_SMTC |
39 | /* | 38 | /* |
@@ -43,8 +42,7 @@ void __cpuinit synchronise_count_master(void) | |||
43 | return; | 42 | return; |
44 | #endif | 43 | #endif |
45 | 44 | ||
46 | printk(KERN_INFO "Synchronize counters across %u CPUs: ", | 45 | printk(KERN_INFO "Synchronize counters for CPU %u: ", cpu); |
47 | num_online_cpus()); | ||
48 | 46 | ||
49 | local_irq_save(flags); | 47 | local_irq_save(flags); |
50 | 48 | ||
@@ -52,7 +50,7 @@ void __cpuinit synchronise_count_master(void) | |||
52 | * Notify the slaves that it's time to start | 50 | * Notify the slaves that it's time to start |
53 | */ | 51 | */ |
54 | atomic_set(&count_reference, read_c0_count()); | 52 | atomic_set(&count_reference, read_c0_count()); |
55 | atomic_set(&count_start_flag, 1); | 53 | atomic_set(&count_start_flag, cpu); |
56 | smp_wmb(); | 54 | smp_wmb(); |
57 | 55 | ||
58 | /* Count will be initialised to current timer for all CPU's */ | 56 | /* Count will be initialised to current timer for all CPU's */ |
@@ -69,10 +67,9 @@ void __cpuinit synchronise_count_master(void) | |||
69 | * two CPUs. | 67 | * two CPUs. |
70 | */ | 68 | */ |
71 | 69 | ||
72 | nslaves = num_online_cpus()-1; | ||
73 | for (i = 0; i < NR_LOOPS; i++) { | 70 | for (i = 0; i < NR_LOOPS; i++) { |
74 | /* slaves loop on '!= ncpus' */ | 71 | /* slaves loop on '!= 2' */ |
75 | while (atomic_read(&count_count_start) != nslaves) | 72 | while (atomic_read(&count_count_start) != 1) |
76 | mb(); | 73 | mb(); |
77 | atomic_set(&count_count_stop, 0); | 74 | atomic_set(&count_count_stop, 0); |
78 | smp_wmb(); | 75 | smp_wmb(); |
@@ -89,7 +86,7 @@ void __cpuinit synchronise_count_master(void) | |||
89 | /* | 86 | /* |
90 | * Wait for all slaves to leave the synchronization point: | 87 | * Wait for all slaves to leave the synchronization point: |
91 | */ | 88 | */ |
92 | while (atomic_read(&count_count_stop) != nslaves) | 89 | while (atomic_read(&count_count_stop) != 1) |
93 | mb(); | 90 | mb(); |
94 | atomic_set(&count_count_start, 0); | 91 | atomic_set(&count_count_start, 0); |
95 | smp_wmb(); | 92 | smp_wmb(); |
@@ -97,6 +94,7 @@ void __cpuinit synchronise_count_master(void) | |||
97 | } | 94 | } |
98 | /* Arrange for an interrupt in a short while */ | 95 | /* Arrange for an interrupt in a short while */ |
99 | write_c0_compare(read_c0_count() + COUNTON); | 96 | write_c0_compare(read_c0_count() + COUNTON); |
97 | atomic_set(&count_start_flag, 0); | ||
100 | 98 | ||
101 | local_irq_restore(flags); | 99 | local_irq_restore(flags); |
102 | 100 | ||
@@ -108,11 +106,10 @@ void __cpuinit synchronise_count_master(void) | |||
108 | printk("done.\n"); | 106 | printk("done.\n"); |
109 | } | 107 | } |
110 | 108 | ||
111 | void __cpuinit synchronise_count_slave(void) | 109 | void __cpuinit synchronise_count_slave(int cpu) |
112 | { | 110 | { |
113 | int i; | 111 | int i; |
114 | unsigned int initcount; | 112 | unsigned int initcount; |
115 | int ncpus; | ||
116 | 113 | ||
117 | #ifdef CONFIG_MIPS_MT_SMTC | 114 | #ifdef CONFIG_MIPS_MT_SMTC |
118 | /* | 115 | /* |
@@ -127,16 +124,15 @@ void __cpuinit synchronise_count_slave(void) | |||
127 | * so we first wait for the master to say everyone is ready | 124 | * so we first wait for the master to say everyone is ready |
128 | */ | 125 | */ |
129 | 126 | ||
130 | while (!atomic_read(&count_start_flag)) | 127 | while (atomic_read(&count_start_flag) != cpu) |
131 | mb(); | 128 | mb(); |
132 | 129 | ||
133 | /* Count will be initialised to next expire for all CPU's */ | 130 | /* Count will be initialised to next expire for all CPU's */ |
134 | initcount = atomic_read(&count_reference); | 131 | initcount = atomic_read(&count_reference); |
135 | 132 | ||
136 | ncpus = num_online_cpus(); | ||
137 | for (i = 0; i < NR_LOOPS; i++) { | 133 | for (i = 0; i < NR_LOOPS; i++) { |
138 | atomic_inc(&count_count_start); | 134 | atomic_inc(&count_count_start); |
139 | while (atomic_read(&count_count_start) != ncpus) | 135 | while (atomic_read(&count_count_start) != 2) |
140 | mb(); | 136 | mb(); |
141 | 137 | ||
142 | /* | 138 | /* |
@@ -146,7 +142,7 @@ void __cpuinit synchronise_count_slave(void) | |||
146 | write_c0_count(initcount); | 142 | write_c0_count(initcount); |
147 | 143 | ||
148 | atomic_inc(&count_count_stop); | 144 | atomic_inc(&count_count_stop); |
149 | while (atomic_read(&count_count_stop) != ncpus) | 145 | while (atomic_read(&count_count_stop) != 2) |
150 | mb(); | 146 | mb(); |
151 | } | 147 | } |
152 | /* Arrange for an interrupt in a short while */ | 148 | /* Arrange for an interrupt in a short while */ |