aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/module.c43
-rw-r--r--arch/mips/kernel/smp.c4
-rw-r--r--arch/mips/kernel/sync-r4k.c26
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
42static struct mips_hi16 *mips_hi16_list;
43
44static LIST_HEAD(dbe_list); 42static LIST_HEAD(dbe_list);
45static DEFINE_SPINLOCK(dbe_lock); 43static 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
143static 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
145static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) 154static 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
203out_danger: 211out_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)
173void __init smp_cpus_done(unsigned int max_cpus) 173void __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
31void __cpuinit synchronise_count_master(void) 31void __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
111void __cpuinit synchronise_count_slave(void) 109void __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 */