diff options
-rw-r--r-- | arch/x86/Kconfig | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/irq.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/pgtable_types.h | 6 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/apic/vector.c | 221 | ||||
-rw-r--r-- | arch/x86/kernel/apic/x2apic_uv_x.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/head64.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/irq.c | 11 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 4 | ||||
-rw-r--r-- | arch/x86/platform/efi/quirks.c | 17 | ||||
-rw-r--r-- | arch/x86/platform/intel-mid/intel-mid.c | 8 | ||||
-rw-r--r-- | arch/x86/platform/intel-quark/imr.c | 18 |
12 files changed, 209 insertions, 103 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 330e738ccfc1..9af2e6338400 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -509,11 +509,10 @@ config X86_INTEL_CE | |||
509 | 509 | ||
510 | config X86_INTEL_MID | 510 | config X86_INTEL_MID |
511 | bool "Intel MID platform support" | 511 | bool "Intel MID platform support" |
512 | depends on X86_32 | ||
513 | depends on X86_EXTENDED_PLATFORM | 512 | depends on X86_EXTENDED_PLATFORM |
514 | depends on X86_PLATFORM_DEVICES | 513 | depends on X86_PLATFORM_DEVICES |
515 | depends on PCI | 514 | depends on PCI |
516 | depends on PCI_GOANY | 515 | depends on X86_64 || (PCI_GOANY && X86_32) |
517 | depends on X86_IO_APIC | 516 | depends on X86_IO_APIC |
518 | select SFI | 517 | select SFI |
519 | select I2C | 518 | select I2C |
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 881b4768644a..e7de5c9a4fbd 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h | |||
@@ -23,11 +23,13 @@ extern void irq_ctx_init(int cpu); | |||
23 | 23 | ||
24 | #define __ARCH_HAS_DO_SOFTIRQ | 24 | #define __ARCH_HAS_DO_SOFTIRQ |
25 | 25 | ||
26 | struct irq_desc; | ||
27 | |||
26 | #ifdef CONFIG_HOTPLUG_CPU | 28 | #ifdef CONFIG_HOTPLUG_CPU |
27 | #include <linux/cpumask.h> | 29 | #include <linux/cpumask.h> |
28 | extern int check_irq_vectors_for_cpu_disable(void); | 30 | extern int check_irq_vectors_for_cpu_disable(void); |
29 | extern void fixup_irqs(void); | 31 | extern void fixup_irqs(void); |
30 | extern void irq_force_complete_move(int); | 32 | extern void irq_force_complete_move(struct irq_desc *desc); |
31 | #endif | 33 | #endif |
32 | 34 | ||
33 | #ifdef CONFIG_HAVE_KVM | 35 | #ifdef CONFIG_HAVE_KVM |
@@ -37,7 +39,6 @@ extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void)); | |||
37 | extern void (*x86_platform_ipi_callback)(void); | 39 | extern void (*x86_platform_ipi_callback)(void); |
38 | extern void native_init_IRQ(void); | 40 | extern void native_init_IRQ(void); |
39 | 41 | ||
40 | struct irq_desc; | ||
41 | extern bool handle_irq(struct irq_desc *desc, struct pt_regs *regs); | 42 | extern bool handle_irq(struct irq_desc *desc, struct pt_regs *regs); |
42 | 43 | ||
43 | extern __visible unsigned int do_IRQ(struct pt_regs *regs); | 44 | extern __visible unsigned int do_IRQ(struct pt_regs *regs); |
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 04c27a013165..4432ab7f407c 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h | |||
@@ -366,20 +366,18 @@ static inline enum page_cache_mode pgprot2cachemode(pgprot_t pgprot) | |||
366 | } | 366 | } |
367 | static inline pgprot_t pgprot_4k_2_large(pgprot_t pgprot) | 367 | static inline pgprot_t pgprot_4k_2_large(pgprot_t pgprot) |
368 | { | 368 | { |
369 | pgprotval_t val = pgprot_val(pgprot); | ||
369 | pgprot_t new; | 370 | pgprot_t new; |
370 | unsigned long val; | ||
371 | 371 | ||
372 | val = pgprot_val(pgprot); | ||
373 | pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) | | 372 | pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) | |
374 | ((val & _PAGE_PAT) << (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT)); | 373 | ((val & _PAGE_PAT) << (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT)); |
375 | return new; | 374 | return new; |
376 | } | 375 | } |
377 | static inline pgprot_t pgprot_large_2_4k(pgprot_t pgprot) | 376 | static inline pgprot_t pgprot_large_2_4k(pgprot_t pgprot) |
378 | { | 377 | { |
378 | pgprotval_t val = pgprot_val(pgprot); | ||
379 | pgprot_t new; | 379 | pgprot_t new; |
380 | unsigned long val; | ||
381 | 380 | ||
382 | val = pgprot_val(pgprot); | ||
383 | pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) | | 381 | pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) | |
384 | ((val & _PAGE_PAT_LARGE) >> | 382 | ((val & _PAGE_PAT_LARGE) >> |
385 | (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT)); | 383 | (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT)); |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index f25321894ad2..fdb0fbfb1197 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -2521,6 +2521,7 @@ void __init setup_ioapic_dest(void) | |||
2521 | { | 2521 | { |
2522 | int pin, ioapic, irq, irq_entry; | 2522 | int pin, ioapic, irq, irq_entry; |
2523 | const struct cpumask *mask; | 2523 | const struct cpumask *mask; |
2524 | struct irq_desc *desc; | ||
2524 | struct irq_data *idata; | 2525 | struct irq_data *idata; |
2525 | struct irq_chip *chip; | 2526 | struct irq_chip *chip; |
2526 | 2527 | ||
@@ -2536,7 +2537,9 @@ void __init setup_ioapic_dest(void) | |||
2536 | if (irq < 0 || !mp_init_irq_at_boot(ioapic, irq)) | 2537 | if (irq < 0 || !mp_init_irq_at_boot(ioapic, irq)) |
2537 | continue; | 2538 | continue; |
2538 | 2539 | ||
2539 | idata = irq_get_irq_data(irq); | 2540 | desc = irq_to_desc(irq); |
2541 | raw_spin_lock_irq(&desc->lock); | ||
2542 | idata = irq_desc_get_irq_data(desc); | ||
2540 | 2543 | ||
2541 | /* | 2544 | /* |
2542 | * Honour affinities which have been set in early boot | 2545 | * Honour affinities which have been set in early boot |
@@ -2550,6 +2553,7 @@ void __init setup_ioapic_dest(void) | |||
2550 | /* Might be lapic_chip for irq 0 */ | 2553 | /* Might be lapic_chip for irq 0 */ |
2551 | if (chip->irq_set_affinity) | 2554 | if (chip->irq_set_affinity) |
2552 | chip->irq_set_affinity(idata, mask, false); | 2555 | chip->irq_set_affinity(idata, mask, false); |
2556 | raw_spin_unlock_irq(&desc->lock); | ||
2553 | } | 2557 | } |
2554 | } | 2558 | } |
2555 | #endif | 2559 | #endif |
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 908cb37da171..3b670df4ba7b 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c | |||
@@ -31,7 +31,7 @@ struct apic_chip_data { | |||
31 | struct irq_domain *x86_vector_domain; | 31 | struct irq_domain *x86_vector_domain; |
32 | EXPORT_SYMBOL_GPL(x86_vector_domain); | 32 | EXPORT_SYMBOL_GPL(x86_vector_domain); |
33 | static DEFINE_RAW_SPINLOCK(vector_lock); | 33 | static DEFINE_RAW_SPINLOCK(vector_lock); |
34 | static cpumask_var_t vector_cpumask; | 34 | static cpumask_var_t vector_cpumask, vector_searchmask, searched_cpumask; |
35 | static struct irq_chip lapic_controller; | 35 | static struct irq_chip lapic_controller; |
36 | #ifdef CONFIG_X86_IO_APIC | 36 | #ifdef CONFIG_X86_IO_APIC |
37 | static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY]; | 37 | static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY]; |
@@ -118,35 +118,47 @@ static int __assign_irq_vector(int irq, struct apic_chip_data *d, | |||
118 | */ | 118 | */ |
119 | static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START; | 119 | static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START; |
120 | static int current_offset = VECTOR_OFFSET_START % 16; | 120 | static int current_offset = VECTOR_OFFSET_START % 16; |
121 | int cpu, err; | 121 | int cpu, vector; |
122 | 122 | ||
123 | if (d->move_in_progress) | 123 | /* |
124 | * If there is still a move in progress or the previous move has not | ||
125 | * been cleaned up completely, tell the caller to come back later. | ||
126 | */ | ||
127 | if (d->move_in_progress || | ||
128 | cpumask_intersects(d->old_domain, cpu_online_mask)) | ||
124 | return -EBUSY; | 129 | return -EBUSY; |
125 | 130 | ||
126 | /* Only try and allocate irqs on cpus that are present */ | 131 | /* Only try and allocate irqs on cpus that are present */ |
127 | err = -ENOSPC; | ||
128 | cpumask_clear(d->old_domain); | 132 | cpumask_clear(d->old_domain); |
133 | cpumask_clear(searched_cpumask); | ||
129 | cpu = cpumask_first_and(mask, cpu_online_mask); | 134 | cpu = cpumask_first_and(mask, cpu_online_mask); |
130 | while (cpu < nr_cpu_ids) { | 135 | while (cpu < nr_cpu_ids) { |
131 | int new_cpu, vector, offset; | 136 | int new_cpu, offset; |
132 | 137 | ||
138 | /* Get the possible target cpus for @mask/@cpu from the apic */ | ||
133 | apic->vector_allocation_domain(cpu, vector_cpumask, mask); | 139 | apic->vector_allocation_domain(cpu, vector_cpumask, mask); |
134 | 140 | ||
141 | /* | ||
142 | * Clear the offline cpus from @vector_cpumask for searching | ||
143 | * and verify whether the result overlaps with @mask. If true, | ||
144 | * then the call to apic->cpu_mask_to_apicid_and() will | ||
145 | * succeed as well. If not, no point in trying to find a | ||
146 | * vector in this mask. | ||
147 | */ | ||
148 | cpumask_and(vector_searchmask, vector_cpumask, cpu_online_mask); | ||
149 | if (!cpumask_intersects(vector_searchmask, mask)) | ||
150 | goto next_cpu; | ||
151 | |||
135 | if (cpumask_subset(vector_cpumask, d->domain)) { | 152 | if (cpumask_subset(vector_cpumask, d->domain)) { |
136 | err = 0; | ||
137 | if (cpumask_equal(vector_cpumask, d->domain)) | 153 | if (cpumask_equal(vector_cpumask, d->domain)) |
138 | break; | 154 | goto success; |
139 | /* | 155 | /* |
140 | * New cpumask using the vector is a proper subset of | 156 | * Mark the cpus which are not longer in the mask for |
141 | * the current in use mask. So cleanup the vector | 157 | * cleanup. |
142 | * allocation for the members that are not used anymore. | ||
143 | */ | 158 | */ |
144 | cpumask_andnot(d->old_domain, d->domain, | 159 | cpumask_andnot(d->old_domain, d->domain, vector_cpumask); |
145 | vector_cpumask); | 160 | vector = d->cfg.vector; |
146 | d->move_in_progress = | 161 | goto update; |
147 | cpumask_intersects(d->old_domain, cpu_online_mask); | ||
148 | cpumask_and(d->domain, d->domain, vector_cpumask); | ||
149 | break; | ||
150 | } | 162 | } |
151 | 163 | ||
152 | vector = current_vector; | 164 | vector = current_vector; |
@@ -158,45 +170,60 @@ next: | |||
158 | vector = FIRST_EXTERNAL_VECTOR + offset; | 170 | vector = FIRST_EXTERNAL_VECTOR + offset; |
159 | } | 171 | } |
160 | 172 | ||
161 | if (unlikely(current_vector == vector)) { | 173 | /* If the search wrapped around, try the next cpu */ |
162 | cpumask_or(d->old_domain, d->old_domain, | 174 | if (unlikely(current_vector == vector)) |
163 | vector_cpumask); | 175 | goto next_cpu; |
164 | cpumask_andnot(vector_cpumask, mask, d->old_domain); | ||
165 | cpu = cpumask_first_and(vector_cpumask, | ||
166 | cpu_online_mask); | ||
167 | continue; | ||
168 | } | ||
169 | 176 | ||
170 | if (test_bit(vector, used_vectors)) | 177 | if (test_bit(vector, used_vectors)) |
171 | goto next; | 178 | goto next; |
172 | 179 | ||
173 | for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) { | 180 | for_each_cpu(new_cpu, vector_searchmask) { |
174 | if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector])) | 181 | if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector])) |
175 | goto next; | 182 | goto next; |
176 | } | 183 | } |
177 | /* Found one! */ | 184 | /* Found one! */ |
178 | current_vector = vector; | 185 | current_vector = vector; |
179 | current_offset = offset; | 186 | current_offset = offset; |
180 | if (d->cfg.vector) { | 187 | /* Schedule the old vector for cleanup on all cpus */ |
188 | if (d->cfg.vector) | ||
181 | cpumask_copy(d->old_domain, d->domain); | 189 | cpumask_copy(d->old_domain, d->domain); |
182 | d->move_in_progress = | 190 | for_each_cpu(new_cpu, vector_searchmask) |
183 | cpumask_intersects(d->old_domain, cpu_online_mask); | ||
184 | } | ||
185 | for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) | ||
186 | per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq); | 191 | per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq); |
187 | d->cfg.vector = vector; | 192 | goto update; |
188 | cpumask_copy(d->domain, vector_cpumask); | ||
189 | err = 0; | ||
190 | break; | ||
191 | } | ||
192 | 193 | ||
193 | if (!err) { | 194 | next_cpu: |
194 | /* cache destination APIC IDs into cfg->dest_apicid */ | 195 | /* |
195 | err = apic->cpu_mask_to_apicid_and(mask, d->domain, | 196 | * We exclude the current @vector_cpumask from the requested |
196 | &d->cfg.dest_apicid); | 197 | * @mask and try again with the next online cpu in the |
198 | * result. We cannot modify @mask, so we use @vector_cpumask | ||
199 | * as a temporary buffer here as it will be reassigned when | ||
200 | * calling apic->vector_allocation_domain() above. | ||
201 | */ | ||
202 | cpumask_or(searched_cpumask, searched_cpumask, vector_cpumask); | ||
203 | cpumask_andnot(vector_cpumask, mask, searched_cpumask); | ||
204 | cpu = cpumask_first_and(vector_cpumask, cpu_online_mask); | ||
205 | continue; | ||
197 | } | 206 | } |
207 | return -ENOSPC; | ||
198 | 208 | ||
199 | return err; | 209 | update: |
210 | /* | ||
211 | * Exclude offline cpus from the cleanup mask and set the | ||
212 | * move_in_progress flag when the result is not empty. | ||
213 | */ | ||
214 | cpumask_and(d->old_domain, d->old_domain, cpu_online_mask); | ||
215 | d->move_in_progress = !cpumask_empty(d->old_domain); | ||
216 | d->cfg.vector = vector; | ||
217 | cpumask_copy(d->domain, vector_cpumask); | ||
218 | success: | ||
219 | /* | ||
220 | * Cache destination APIC IDs into cfg->dest_apicid. This cannot fail | ||
221 | * as we already established, that mask & d->domain & cpu_online_mask | ||
222 | * is not empty. | ||
223 | */ | ||
224 | BUG_ON(apic->cpu_mask_to_apicid_and(mask, d->domain, | ||
225 | &d->cfg.dest_apicid)); | ||
226 | return 0; | ||
200 | } | 227 | } |
201 | 228 | ||
202 | static int assign_irq_vector(int irq, struct apic_chip_data *data, | 229 | static int assign_irq_vector(int irq, struct apic_chip_data *data, |
@@ -226,10 +253,8 @@ static int assign_irq_vector_policy(int irq, int node, | |||
226 | static void clear_irq_vector(int irq, struct apic_chip_data *data) | 253 | static void clear_irq_vector(int irq, struct apic_chip_data *data) |
227 | { | 254 | { |
228 | struct irq_desc *desc; | 255 | struct irq_desc *desc; |
229 | unsigned long flags; | ||
230 | int cpu, vector; | 256 | int cpu, vector; |
231 | 257 | ||
232 | raw_spin_lock_irqsave(&vector_lock, flags); | ||
233 | BUG_ON(!data->cfg.vector); | 258 | BUG_ON(!data->cfg.vector); |
234 | 259 | ||
235 | vector = data->cfg.vector; | 260 | vector = data->cfg.vector; |
@@ -239,10 +264,13 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data) | |||
239 | data->cfg.vector = 0; | 264 | data->cfg.vector = 0; |
240 | cpumask_clear(data->domain); | 265 | cpumask_clear(data->domain); |
241 | 266 | ||
242 | if (likely(!data->move_in_progress)) { | 267 | /* |
243 | raw_spin_unlock_irqrestore(&vector_lock, flags); | 268 | * If move is in progress or the old_domain mask is not empty, |
269 | * i.e. the cleanup IPI has not been processed yet, we need to remove | ||
270 | * the old references to desc from all cpus vector tables. | ||
271 | */ | ||
272 | if (!data->move_in_progress && cpumask_empty(data->old_domain)) | ||
244 | return; | 273 | return; |
245 | } | ||
246 | 274 | ||
247 | desc = irq_to_desc(irq); | 275 | desc = irq_to_desc(irq); |
248 | for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) { | 276 | for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) { |
@@ -255,7 +283,6 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data) | |||
255 | } | 283 | } |
256 | } | 284 | } |
257 | data->move_in_progress = 0; | 285 | data->move_in_progress = 0; |
258 | raw_spin_unlock_irqrestore(&vector_lock, flags); | ||
259 | } | 286 | } |
260 | 287 | ||
261 | void init_irq_alloc_info(struct irq_alloc_info *info, | 288 | void init_irq_alloc_info(struct irq_alloc_info *info, |
@@ -276,19 +303,24 @@ void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src) | |||
276 | static void x86_vector_free_irqs(struct irq_domain *domain, | 303 | static void x86_vector_free_irqs(struct irq_domain *domain, |
277 | unsigned int virq, unsigned int nr_irqs) | 304 | unsigned int virq, unsigned int nr_irqs) |
278 | { | 305 | { |
306 | struct apic_chip_data *apic_data; | ||
279 | struct irq_data *irq_data; | 307 | struct irq_data *irq_data; |
308 | unsigned long flags; | ||
280 | int i; | 309 | int i; |
281 | 310 | ||
282 | for (i = 0; i < nr_irqs; i++) { | 311 | for (i = 0; i < nr_irqs; i++) { |
283 | irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i); | 312 | irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i); |
284 | if (irq_data && irq_data->chip_data) { | 313 | if (irq_data && irq_data->chip_data) { |
314 | raw_spin_lock_irqsave(&vector_lock, flags); | ||
285 | clear_irq_vector(virq + i, irq_data->chip_data); | 315 | clear_irq_vector(virq + i, irq_data->chip_data); |
286 | free_apic_chip_data(irq_data->chip_data); | 316 | apic_data = irq_data->chip_data; |
317 | irq_domain_reset_irq_data(irq_data); | ||
318 | raw_spin_unlock_irqrestore(&vector_lock, flags); | ||
319 | free_apic_chip_data(apic_data); | ||
287 | #ifdef CONFIG_X86_IO_APIC | 320 | #ifdef CONFIG_X86_IO_APIC |
288 | if (virq + i < nr_legacy_irqs()) | 321 | if (virq + i < nr_legacy_irqs()) |
289 | legacy_irq_data[virq + i] = NULL; | 322 | legacy_irq_data[virq + i] = NULL; |
290 | #endif | 323 | #endif |
291 | irq_domain_reset_irq_data(irq_data); | ||
292 | } | 324 | } |
293 | } | 325 | } |
294 | } | 326 | } |
@@ -406,6 +438,8 @@ int __init arch_early_irq_init(void) | |||
406 | arch_init_htirq_domain(x86_vector_domain); | 438 | arch_init_htirq_domain(x86_vector_domain); |
407 | 439 | ||
408 | BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL)); | 440 | BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL)); |
441 | BUG_ON(!alloc_cpumask_var(&vector_searchmask, GFP_KERNEL)); | ||
442 | BUG_ON(!alloc_cpumask_var(&searched_cpumask, GFP_KERNEL)); | ||
409 | 443 | ||
410 | return arch_early_ioapic_init(); | 444 | return arch_early_ioapic_init(); |
411 | } | 445 | } |
@@ -494,14 +528,7 @@ static int apic_set_affinity(struct irq_data *irq_data, | |||
494 | return -EINVAL; | 528 | return -EINVAL; |
495 | 529 | ||
496 | err = assign_irq_vector(irq, data, dest); | 530 | err = assign_irq_vector(irq, data, dest); |
497 | if (err) { | 531 | return err ? err : IRQ_SET_MASK_OK; |
498 | if (assign_irq_vector(irq, data, | ||
499 | irq_data_get_affinity_mask(irq_data))) | ||
500 | pr_err("Failed to recover vector for irq %d\n", irq); | ||
501 | return err; | ||
502 | } | ||
503 | |||
504 | return IRQ_SET_MASK_OK; | ||
505 | } | 532 | } |
506 | 533 | ||
507 | static struct irq_chip lapic_controller = { | 534 | static struct irq_chip lapic_controller = { |
@@ -513,20 +540,12 @@ static struct irq_chip lapic_controller = { | |||
513 | #ifdef CONFIG_SMP | 540 | #ifdef CONFIG_SMP |
514 | static void __send_cleanup_vector(struct apic_chip_data *data) | 541 | static void __send_cleanup_vector(struct apic_chip_data *data) |
515 | { | 542 | { |
516 | cpumask_var_t cleanup_mask; | 543 | raw_spin_lock(&vector_lock); |
517 | 544 | cpumask_and(data->old_domain, data->old_domain, cpu_online_mask); | |
518 | if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { | ||
519 | unsigned int i; | ||
520 | |||
521 | for_each_cpu_and(i, data->old_domain, cpu_online_mask) | ||
522 | apic->send_IPI_mask(cpumask_of(i), | ||
523 | IRQ_MOVE_CLEANUP_VECTOR); | ||
524 | } else { | ||
525 | cpumask_and(cleanup_mask, data->old_domain, cpu_online_mask); | ||
526 | apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); | ||
527 | free_cpumask_var(cleanup_mask); | ||
528 | } | ||
529 | data->move_in_progress = 0; | 545 | data->move_in_progress = 0; |
546 | if (!cpumask_empty(data->old_domain)) | ||
547 | apic->send_IPI_mask(data->old_domain, IRQ_MOVE_CLEANUP_VECTOR); | ||
548 | raw_spin_unlock(&vector_lock); | ||
530 | } | 549 | } |
531 | 550 | ||
532 | void send_cleanup_vector(struct irq_cfg *cfg) | 551 | void send_cleanup_vector(struct irq_cfg *cfg) |
@@ -570,12 +589,25 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) | |||
570 | goto unlock; | 589 | goto unlock; |
571 | 590 | ||
572 | /* | 591 | /* |
573 | * Check if the irq migration is in progress. If so, we | 592 | * Nothing to cleanup if irq migration is in progress |
574 | * haven't received the cleanup request yet for this irq. | 593 | * or this cpu is not set in the cleanup mask. |
575 | */ | 594 | */ |
576 | if (data->move_in_progress) | 595 | if (data->move_in_progress || |
596 | !cpumask_test_cpu(me, data->old_domain)) | ||
577 | goto unlock; | 597 | goto unlock; |
578 | 598 | ||
599 | /* | ||
600 | * We have two cases to handle here: | ||
601 | * 1) vector is unchanged but the target mask got reduced | ||
602 | * 2) vector and the target mask has changed | ||
603 | * | ||
604 | * #1 is obvious, but in #2 we have two vectors with the same | ||
605 | * irq descriptor: the old and the new vector. So we need to | ||
606 | * make sure that we only cleanup the old vector. The new | ||
607 | * vector has the current @vector number in the config and | ||
608 | * this cpu is part of the target mask. We better leave that | ||
609 | * one alone. | ||
610 | */ | ||
579 | if (vector == data->cfg.vector && | 611 | if (vector == data->cfg.vector && |
580 | cpumask_test_cpu(me, data->domain)) | 612 | cpumask_test_cpu(me, data->domain)) |
581 | goto unlock; | 613 | goto unlock; |
@@ -593,6 +625,7 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) | |||
593 | goto unlock; | 625 | goto unlock; |
594 | } | 626 | } |
595 | __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); | 627 | __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); |
628 | cpumask_clear_cpu(me, data->old_domain); | ||
596 | unlock: | 629 | unlock: |
597 | raw_spin_unlock(&desc->lock); | 630 | raw_spin_unlock(&desc->lock); |
598 | } | 631 | } |
@@ -621,12 +654,48 @@ void irq_complete_move(struct irq_cfg *cfg) | |||
621 | __irq_complete_move(cfg, ~get_irq_regs()->orig_ax); | 654 | __irq_complete_move(cfg, ~get_irq_regs()->orig_ax); |
622 | } | 655 | } |
623 | 656 | ||
624 | void irq_force_complete_move(int irq) | 657 | /* |
658 | * Called with @desc->lock held and interrupts disabled. | ||
659 | */ | ||
660 | void irq_force_complete_move(struct irq_desc *desc) | ||
625 | { | 661 | { |
626 | struct irq_cfg *cfg = irq_cfg(irq); | 662 | struct irq_data *irqdata = irq_desc_get_irq_data(desc); |
663 | struct apic_chip_data *data = apic_chip_data(irqdata); | ||
664 | struct irq_cfg *cfg = data ? &data->cfg : NULL; | ||
627 | 665 | ||
628 | if (cfg) | 666 | if (!cfg) |
629 | __irq_complete_move(cfg, cfg->vector); | 667 | return; |
668 | |||
669 | __irq_complete_move(cfg, cfg->vector); | ||
670 | |||
671 | /* | ||
672 | * This is tricky. If the cleanup of @data->old_domain has not been | ||
673 | * done yet, then the following setaffinity call will fail with | ||
674 | * -EBUSY. This can leave the interrupt in a stale state. | ||
675 | * | ||
676 | * The cleanup cannot make progress because we hold @desc->lock. So in | ||
677 | * case @data->old_domain is not yet cleaned up, we need to drop the | ||
678 | * lock and acquire it again. @desc cannot go away, because the | ||
679 | * hotplug code holds the sparse irq lock. | ||
680 | */ | ||
681 | raw_spin_lock(&vector_lock); | ||
682 | /* Clean out all offline cpus (including ourself) first. */ | ||
683 | cpumask_and(data->old_domain, data->old_domain, cpu_online_mask); | ||
684 | while (!cpumask_empty(data->old_domain)) { | ||
685 | raw_spin_unlock(&vector_lock); | ||
686 | raw_spin_unlock(&desc->lock); | ||
687 | cpu_relax(); | ||
688 | raw_spin_lock(&desc->lock); | ||
689 | /* | ||
690 | * Reevaluate apic_chip_data. It might have been cleared after | ||
691 | * we dropped @desc->lock. | ||
692 | */ | ||
693 | data = apic_chip_data(irqdata); | ||
694 | if (!data) | ||
695 | return; | ||
696 | raw_spin_lock(&vector_lock); | ||
697 | } | ||
698 | raw_spin_unlock(&vector_lock); | ||
630 | } | 699 | } |
631 | #endif | 700 | #endif |
632 | 701 | ||
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index d760c6bb37b5..624db00583f4 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c | |||
@@ -889,7 +889,10 @@ void __init uv_system_init(void) | |||
889 | return; | 889 | return; |
890 | } | 890 | } |
891 | pr_info("UV: Found %s hub\n", hub); | 891 | pr_info("UV: Found %s hub\n", hub); |
892 | map_low_mmrs(); | 892 | |
893 | /* We now only need to map the MMRs on UV1 */ | ||
894 | if (is_uv1_hub()) | ||
895 | map_low_mmrs(); | ||
893 | 896 | ||
894 | m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR ); | 897 | m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR ); |
895 | m_val = m_n_config.s.m_skt; | 898 | m_val = m_n_config.s.m_skt; |
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index f129a9af6357..2c0f3407bd1f 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c | |||
@@ -192,5 +192,13 @@ void __init x86_64_start_reservations(char *real_mode_data) | |||
192 | 192 | ||
193 | reserve_ebda_region(); | 193 | reserve_ebda_region(); |
194 | 194 | ||
195 | switch (boot_params.hdr.hardware_subarch) { | ||
196 | case X86_SUBARCH_INTEL_MID: | ||
197 | x86_intel_mid_early_setup(); | ||
198 | break; | ||
199 | default: | ||
200 | break; | ||
201 | } | ||
202 | |||
195 | start_kernel(); | 203 | start_kernel(); |
196 | } | 204 | } |
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index f8062aaf5df9..61521dc19c10 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c | |||
@@ -462,7 +462,7 @@ void fixup_irqs(void) | |||
462 | * non intr-remapping case, we can't wait till this interrupt | 462 | * non intr-remapping case, we can't wait till this interrupt |
463 | * arrives at this cpu before completing the irq move. | 463 | * arrives at this cpu before completing the irq move. |
464 | */ | 464 | */ |
465 | irq_force_complete_move(irq); | 465 | irq_force_complete_move(desc); |
466 | 466 | ||
467 | if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { | 467 | if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { |
468 | break_affinity = 1; | 468 | break_affinity = 1; |
@@ -470,6 +470,15 @@ void fixup_irqs(void) | |||
470 | } | 470 | } |
471 | 471 | ||
472 | chip = irq_data_get_irq_chip(data); | 472 | chip = irq_data_get_irq_chip(data); |
473 | /* | ||
474 | * The interrupt descriptor might have been cleaned up | ||
475 | * already, but it is not yet removed from the radix tree | ||
476 | */ | ||
477 | if (!chip) { | ||
478 | raw_spin_unlock(&desc->lock); | ||
479 | continue; | ||
480 | } | ||
481 | |||
473 | if (!irqd_can_move_in_process_context(data) && chip->irq_mask) | 482 | if (!irqd_can_move_in_process_context(data) && chip->irq_mask) |
474 | chip->irq_mask(data); | 483 | chip->irq_mask(data); |
475 | 484 | ||
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index fc6a4c8f6e2a..2440814b0069 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -33,7 +33,7 @@ struct cpa_data { | |||
33 | pgd_t *pgd; | 33 | pgd_t *pgd; |
34 | pgprot_t mask_set; | 34 | pgprot_t mask_set; |
35 | pgprot_t mask_clr; | 35 | pgprot_t mask_clr; |
36 | int numpages; | 36 | unsigned long numpages; |
37 | int flags; | 37 | int flags; |
38 | unsigned long pfn; | 38 | unsigned long pfn; |
39 | unsigned force_split : 1; | 39 | unsigned force_split : 1; |
@@ -1350,7 +1350,7 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias) | |||
1350 | * CPA operation. Either a large page has been | 1350 | * CPA operation. Either a large page has been |
1351 | * preserved or a single page update happened. | 1351 | * preserved or a single page update happened. |
1352 | */ | 1352 | */ |
1353 | BUG_ON(cpa->numpages > numpages); | 1353 | BUG_ON(cpa->numpages > numpages || !cpa->numpages); |
1354 | numpages -= cpa->numpages; | 1354 | numpages -= cpa->numpages; |
1355 | if (cpa->flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) | 1355 | if (cpa->flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) |
1356 | cpa->curpage++; | 1356 | cpa->curpage++; |
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 1c7380da65ff..2d66db8f80f9 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/memblock.h> | 8 | #include <linux/memblock.h> |
9 | #include <linux/bootmem.h> | 9 | #include <linux/bootmem.h> |
10 | #include <linux/acpi.h> | 10 | #include <linux/acpi.h> |
11 | #include <linux/dmi.h> | ||
11 | #include <asm/efi.h> | 12 | #include <asm/efi.h> |
12 | #include <asm/uv/uv.h> | 13 | #include <asm/uv/uv.h> |
13 | 14 | ||
@@ -248,6 +249,16 @@ out: | |||
248 | return ret; | 249 | return ret; |
249 | } | 250 | } |
250 | 251 | ||
252 | static const struct dmi_system_id sgi_uv1_dmi[] = { | ||
253 | { NULL, "SGI UV1", | ||
254 | { DMI_MATCH(DMI_PRODUCT_NAME, "Stoutland Platform"), | ||
255 | DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"), | ||
256 | DMI_MATCH(DMI_BIOS_VENDOR, "SGI.COM"), | ||
257 | } | ||
258 | }, | ||
259 | { } /* NULL entry stops DMI scanning */ | ||
260 | }; | ||
261 | |||
251 | void __init efi_apply_memmap_quirks(void) | 262 | void __init efi_apply_memmap_quirks(void) |
252 | { | 263 | { |
253 | /* | 264 | /* |
@@ -260,10 +271,8 @@ void __init efi_apply_memmap_quirks(void) | |||
260 | efi_unmap_memmap(); | 271 | efi_unmap_memmap(); |
261 | } | 272 | } |
262 | 273 | ||
263 | /* | 274 | /* UV2+ BIOS has a fix for this issue. UV1 still needs the quirk. */ |
264 | * UV doesn't support the new EFI pagetable mapping yet. | 275 | if (dmi_check_system(sgi_uv1_dmi)) |
265 | */ | ||
266 | if (is_uv_system()) | ||
267 | set_bit(EFI_OLD_MEMMAP, &efi.flags); | 276 | set_bit(EFI_OLD_MEMMAP, &efi.flags); |
268 | } | 277 | } |
269 | 278 | ||
diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c index 1bbc21e2e4ae..90bb997ed0a2 100644 --- a/arch/x86/platform/intel-mid/intel-mid.c +++ b/arch/x86/platform/intel-mid/intel-mid.c | |||
@@ -138,7 +138,7 @@ static void intel_mid_arch_setup(void) | |||
138 | intel_mid_ops = get_intel_mid_ops[__intel_mid_cpu_chip](); | 138 | intel_mid_ops = get_intel_mid_ops[__intel_mid_cpu_chip](); |
139 | else { | 139 | else { |
140 | intel_mid_ops = get_intel_mid_ops[INTEL_MID_CPU_CHIP_PENWELL](); | 140 | intel_mid_ops = get_intel_mid_ops[INTEL_MID_CPU_CHIP_PENWELL](); |
141 | pr_info("ARCH: Unknown SoC, assuming PENWELL!\n"); | 141 | pr_info("ARCH: Unknown SoC, assuming Penwell!\n"); |
142 | } | 142 | } |
143 | 143 | ||
144 | out: | 144 | out: |
@@ -214,12 +214,10 @@ static inline int __init setup_x86_intel_mid_timer(char *arg) | |||
214 | else if (strcmp("lapic_and_apbt", arg) == 0) | 214 | else if (strcmp("lapic_and_apbt", arg) == 0) |
215 | intel_mid_timer_options = INTEL_MID_TIMER_LAPIC_APBT; | 215 | intel_mid_timer_options = INTEL_MID_TIMER_LAPIC_APBT; |
216 | else { | 216 | else { |
217 | pr_warn("X86 INTEL_MID timer option %s not recognised" | 217 | pr_warn("X86 INTEL_MID timer option %s not recognised use x86_intel_mid_timer=apbt_only or lapic_and_apbt\n", |
218 | " use x86_intel_mid_timer=apbt_only or lapic_and_apbt\n", | 218 | arg); |
219 | arg); | ||
220 | return -EINVAL; | 219 | return -EINVAL; |
221 | } | 220 | } |
222 | return 0; | 221 | return 0; |
223 | } | 222 | } |
224 | __setup("x86_intel_mid_timer=", setup_x86_intel_mid_timer); | 223 | __setup("x86_intel_mid_timer=", setup_x86_intel_mid_timer); |
225 | |||
diff --git a/arch/x86/platform/intel-quark/imr.c b/arch/x86/platform/intel-quark/imr.c index c1bdafaac3ca..c61b6c332e97 100644 --- a/arch/x86/platform/intel-quark/imr.c +++ b/arch/x86/platform/intel-quark/imr.c | |||
@@ -220,11 +220,12 @@ static int imr_dbgfs_state_show(struct seq_file *s, void *unused) | |||
220 | if (imr_is_enabled(&imr)) { | 220 | if (imr_is_enabled(&imr)) { |
221 | base = imr_to_phys(imr.addr_lo); | 221 | base = imr_to_phys(imr.addr_lo); |
222 | end = imr_to_phys(imr.addr_hi) + IMR_MASK; | 222 | end = imr_to_phys(imr.addr_hi) + IMR_MASK; |
223 | size = end - base + 1; | ||
223 | } else { | 224 | } else { |
224 | base = 0; | 225 | base = 0; |
225 | end = 0; | 226 | end = 0; |
227 | size = 0; | ||
226 | } | 228 | } |
227 | size = end - base; | ||
228 | seq_printf(s, "imr%02i: base=%pa, end=%pa, size=0x%08zx " | 229 | seq_printf(s, "imr%02i: base=%pa, end=%pa, size=0x%08zx " |
229 | "rmask=0x%08x, wmask=0x%08x, %s, %s\n", i, | 230 | "rmask=0x%08x, wmask=0x%08x, %s, %s\n", i, |
230 | &base, &end, size, imr.rmask, imr.wmask, | 231 | &base, &end, size, imr.rmask, imr.wmask, |
@@ -579,6 +580,7 @@ static void __init imr_fixup_memmap(struct imr_device *idev) | |||
579 | { | 580 | { |
580 | phys_addr_t base = virt_to_phys(&_text); | 581 | phys_addr_t base = virt_to_phys(&_text); |
581 | size_t size = virt_to_phys(&__end_rodata) - base; | 582 | size_t size = virt_to_phys(&__end_rodata) - base; |
583 | unsigned long start, end; | ||
582 | int i; | 584 | int i; |
583 | int ret; | 585 | int ret; |
584 | 586 | ||
@@ -586,18 +588,24 @@ static void __init imr_fixup_memmap(struct imr_device *idev) | |||
586 | for (i = 0; i < idev->max_imr; i++) | 588 | for (i = 0; i < idev->max_imr; i++) |
587 | imr_clear(i); | 589 | imr_clear(i); |
588 | 590 | ||
591 | start = (unsigned long)_text; | ||
592 | end = (unsigned long)__end_rodata - 1; | ||
593 | |||
589 | /* | 594 | /* |
590 | * Setup a locked IMR around the physical extent of the kernel | 595 | * Setup a locked IMR around the physical extent of the kernel |
591 | * from the beginning of the .text secton to the end of the | 596 | * from the beginning of the .text secton to the end of the |
592 | * .rodata section as one physically contiguous block. | 597 | * .rodata section as one physically contiguous block. |
598 | * | ||
599 | * We don't round up @size since it is already PAGE_SIZE aligned. | ||
600 | * See vmlinux.lds.S for details. | ||
593 | */ | 601 | */ |
594 | ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, true); | 602 | ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, true); |
595 | if (ret < 0) { | 603 | if (ret < 0) { |
596 | pr_err("unable to setup IMR for kernel: (%p - %p)\n", | 604 | pr_err("unable to setup IMR for kernel: %zu KiB (%lx - %lx)\n", |
597 | &_text, &__end_rodata); | 605 | size / 1024, start, end); |
598 | } else { | 606 | } else { |
599 | pr_info("protecting kernel .text - .rodata: %zu KiB (%p - %p)\n", | 607 | pr_info("protecting kernel .text - .rodata: %zu KiB (%lx - %lx)\n", |
600 | size / 1024, &_text, &__end_rodata); | 608 | size / 1024, start, end); |
601 | } | 609 | } |
602 | 610 | ||
603 | } | 611 | } |