1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/interrupt.h>
14#include <linux/init.h>
15#include <linux/compiler.h>
16#include <linux/slab.h>
17#include <asm/irqdomain.h>
18#include <asm/hw_irq.h>
19#include <asm/apic.h>
20#include <asm/i8259.h>
21#include <asm/desc.h>
22#include <asm/irq_remapping.h>
23
24struct apic_chip_data {
25 struct irq_cfg cfg;
26 cpumask_var_t domain;
27 cpumask_var_t old_domain;
28 u8 move_in_progress : 1;
29};
30
31struct irq_domain *x86_vector_domain;
32EXPORT_SYMBOL_GPL(x86_vector_domain);
33static DEFINE_RAW_SPINLOCK(vector_lock);
34static cpumask_var_t vector_cpumask, vector_searchmask, searched_cpumask;
35static struct irq_chip lapic_controller;
36#ifdef CONFIG_X86_IO_APIC
37static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
38#endif
39
40void lock_vector_lock(void)
41{
42
43
44
45 raw_spin_lock(&vector_lock);
46}
47
48void unlock_vector_lock(void)
49{
50 raw_spin_unlock(&vector_lock);
51}
52
53static struct apic_chip_data *apic_chip_data(struct irq_data *irq_data)
54{
55 if (!irq_data)
56 return NULL;
57
58 while (irq_data->parent_data)
59 irq_data = irq_data->parent_data;
60
61 return irq_data->chip_data;
62}
63
64struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
65{
66 struct apic_chip_data *data = apic_chip_data(irq_data);
67
68 return data ? &data->cfg : NULL;
69}
70EXPORT_SYMBOL_GPL(irqd_cfg);
71
72struct irq_cfg *irq_cfg(unsigned int irq)
73{
74 return irqd_cfg(irq_get_irq_data(irq));
75}
76
77static struct apic_chip_data *alloc_apic_chip_data(int node)
78{
79 struct apic_chip_data *data;
80
81 data = kzalloc_node(sizeof(*data), GFP_KERNEL, node);
82 if (!data)
83 return NULL;
84 if (!zalloc_cpumask_var_node(&data->domain, GFP_KERNEL, node))
85 goto out_data;
86 if (!zalloc_cpumask_var_node(&data->old_domain, GFP_KERNEL, node))
87 goto out_domain;
88 return data;
89out_domain:
90 free_cpumask_var(data->domain);
91out_data:
92 kfree(data);
93 return NULL;
94}
95
96static void free_apic_chip_data(struct apic_chip_data *data)
97{
98 if (data) {
99 free_cpumask_var(data->domain);
100 free_cpumask_var(data->old_domain);
101 kfree(data);
102 }
103}
104
105static int __assign_irq_vector(int irq, struct apic_chip_data *d,
106 const struct cpumask *mask)
107{
108
109
110
111
112
113
114
115
116
117
118
119 static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
120 static int current_offset = VECTOR_OFFSET_START % 16;
121 int cpu, vector;
122
123
124
125
126
127 if (d->move_in_progress ||
128 cpumask_intersects(d->old_domain, cpu_online_mask))
129 return -EBUSY;
130
131
132 cpumask_clear(d->old_domain);
133 cpumask_clear(searched_cpumask);
134 cpu = cpumask_first_and(mask, cpu_online_mask);
135 while (cpu < nr_cpu_ids) {
136 int new_cpu, offset;
137
138
139 apic->vector_allocation_domain(cpu, vector_cpumask, mask);
140
141
142
143
144
145
146
147
148 cpumask_and(vector_searchmask, vector_cpumask, cpu_online_mask);
149 if (!cpumask_intersects(vector_searchmask, mask))
150 goto next_cpu;
151
152 if (cpumask_subset(vector_cpumask, d->domain)) {
153 if (cpumask_equal(vector_cpumask, d->domain))
154 goto success;
155
156
157
158
159 cpumask_andnot(d->old_domain, d->domain, vector_cpumask);
160 vector = d->cfg.vector;
161 goto update;
162 }
163
164 vector = current_vector;
165 offset = current_offset;
166next:
167 vector += 16;
168 if (vector >= first_system_vector) {
169 offset = (offset + 1) % 16;
170 vector = FIRST_EXTERNAL_VECTOR + offset;
171 }
172
173
174 if (unlikely(current_vector == vector))
175 goto next_cpu;
176
177 if (test_bit(vector, used_vectors))
178 goto next;
179
180 for_each_cpu(new_cpu, vector_searchmask) {
181 if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector]))
182 goto next;
183 }
184
185 current_vector = vector;
186 current_offset = offset;
187
188 if (d->cfg.vector)
189 cpumask_copy(d->old_domain, d->domain);
190 for_each_cpu(new_cpu, vector_searchmask)
191 per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq);
192 goto update;
193
194next_cpu:
195
196
197
198
199
200
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;
206 }
207 return -ENOSPC;
208
209update:
210
211
212
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.old_vector = d->move_in_progress ? d->cfg.vector : 0;
217 d->cfg.vector = vector;
218 cpumask_copy(d->domain, vector_cpumask);
219success:
220
221
222
223
224
225 BUG_ON(apic->cpu_mask_to_apicid_and(mask, d->domain,
226 &d->cfg.dest_apicid));
227 return 0;
228}
229
230static int assign_irq_vector(int irq, struct apic_chip_data *data,
231 const struct cpumask *mask)
232{
233 int err;
234 unsigned long flags;
235
236 raw_spin_lock_irqsave(&vector_lock, flags);
237 err = __assign_irq_vector(irq, data, mask);
238 raw_spin_unlock_irqrestore(&vector_lock, flags);
239 return err;
240}
241
242static int assign_irq_vector_policy(int irq, int node,
243 struct apic_chip_data *data,
244 struct irq_alloc_info *info)
245{
246 if (info && info->mask)
247 return assign_irq_vector(irq, data, info->mask);
248 if (node != NUMA_NO_NODE &&
249 assign_irq_vector(irq, data, cpumask_of_node(node)) == 0)
250 return 0;
251 return assign_irq_vector(irq, data, apic->target_cpus());
252}
253
254static void clear_irq_vector(int irq, struct apic_chip_data *data)
255{
256 struct irq_desc *desc;
257 int cpu, vector;
258
259 if (!data->cfg.vector)
260 return;
261
262 vector = data->cfg.vector;
263 for_each_cpu_and(cpu, data->domain, cpu_online_mask)
264 per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
265
266 data->cfg.vector = 0;
267 cpumask_clear(data->domain);
268
269
270
271
272
273
274 if (!data->move_in_progress && cpumask_empty(data->old_domain))
275 return;
276
277 desc = irq_to_desc(irq);
278 for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
279 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
280 vector++) {
281 if (per_cpu(vector_irq, cpu)[vector] != desc)
282 continue;
283 per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
284 break;
285 }
286 }
287 data->move_in_progress = 0;
288}
289
290void init_irq_alloc_info(struct irq_alloc_info *info,
291 const struct cpumask *mask)
292{
293 memset(info, 0, sizeof(*info));
294 info->mask = mask;
295}
296
297void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src)
298{
299 if (src)
300 *dst = *src;
301 else
302 memset(dst, 0, sizeof(*dst));
303}
304
305static void x86_vector_free_irqs(struct irq_domain *domain,
306 unsigned int virq, unsigned int nr_irqs)
307{
308 struct apic_chip_data *apic_data;
309 struct irq_data *irq_data;
310 unsigned long flags;
311 int i;
312
313 for (i = 0; i < nr_irqs; i++) {
314 irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i);
315 if (irq_data && irq_data->chip_data) {
316 raw_spin_lock_irqsave(&vector_lock, flags);
317 clear_irq_vector(virq + i, irq_data->chip_data);
318 apic_data = irq_data->chip_data;
319 irq_domain_reset_irq_data(irq_data);
320 raw_spin_unlock_irqrestore(&vector_lock, flags);
321 free_apic_chip_data(apic_data);
322#ifdef CONFIG_X86_IO_APIC
323 if (virq + i < nr_legacy_irqs())
324 legacy_irq_data[virq + i] = NULL;
325#endif
326 }
327 }
328}
329
330static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
331 unsigned int nr_irqs, void *arg)
332{
333 struct irq_alloc_info *info = arg;
334 struct apic_chip_data *data;
335 struct irq_data *irq_data;
336 int i, err, node;
337
338 if (disable_apic)
339 return -ENXIO;
340
341
342 if ((info->flags & X86_IRQ_ALLOC_CONTIGUOUS_VECTORS) && nr_irqs > 1)
343 return -ENOSYS;
344
345 for (i = 0; i < nr_irqs; i++) {
346 irq_data = irq_domain_get_irq_data(domain, virq + i);
347 BUG_ON(!irq_data);
348 node = irq_data_get_node(irq_data);
349#ifdef CONFIG_X86_IO_APIC
350 if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i])
351 data = legacy_irq_data[virq + i];
352 else
353#endif
354 data = alloc_apic_chip_data(node);
355 if (!data) {
356 err = -ENOMEM;
357 goto error;
358 }
359
360 irq_data->chip = &lapic_controller;
361 irq_data->chip_data = data;
362 irq_data->hwirq = virq + i;
363 err = assign_irq_vector_policy(virq + i, node, data, info);
364 if (err)
365 goto error;
366 }
367
368 return 0;
369
370error:
371 x86_vector_free_irqs(domain, virq, i + 1);
372 return err;
373}
374
375static const struct irq_domain_ops x86_vector_domain_ops = {
376 .alloc = x86_vector_alloc_irqs,
377 .free = x86_vector_free_irqs,
378};
379
380int __init arch_probe_nr_irqs(void)
381{
382 int nr;
383
384 if (nr_irqs > (NR_VECTORS * nr_cpu_ids))
385 nr_irqs = NR_VECTORS * nr_cpu_ids;
386
387 nr = (gsi_top + nr_legacy_irqs()) + 8 * nr_cpu_ids;
388#if defined(CONFIG_PCI_MSI) || defined(CONFIG_HT_IRQ)
389
390
391
392 if (gsi_top <= NR_IRQS_LEGACY)
393 nr += 8 * nr_cpu_ids;
394 else
395 nr += gsi_top * 16;
396#endif
397 if (nr < nr_irqs)
398 nr_irqs = nr;
399
400
401
402
403
404 return legacy_pic->probe();
405}
406
407#ifdef CONFIG_X86_IO_APIC
408static void init_legacy_irqs(void)
409{
410 int i, node = cpu_to_node(0);
411 struct apic_chip_data *data;
412
413
414
415
416
417 for (i = 0; i < nr_legacy_irqs(); i++) {
418 data = legacy_irq_data[i] = alloc_apic_chip_data(node);
419 BUG_ON(!data);
420
421 data->cfg.vector = ISA_IRQ_VECTOR(i);
422 cpumask_setall(data->domain);
423 irq_set_chip_data(i, data);
424 }
425}
426#else
427static void init_legacy_irqs(void) { }
428#endif
429
430int __init arch_early_irq_init(void)
431{
432 init_legacy_irqs();
433
434 x86_vector_domain = irq_domain_add_tree(NULL, &x86_vector_domain_ops,
435 NULL);
436 BUG_ON(x86_vector_domain == NULL);
437 irq_set_default_host(x86_vector_domain);
438
439 arch_init_msi_domain(x86_vector_domain);
440 arch_init_htirq_domain(x86_vector_domain);
441
442 BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL));
443 BUG_ON(!alloc_cpumask_var(&vector_searchmask, GFP_KERNEL));
444 BUG_ON(!alloc_cpumask_var(&searched_cpumask, GFP_KERNEL));
445
446 return arch_early_ioapic_init();
447}
448
449
450static void __setup_vector_irq(int cpu)
451{
452 struct apic_chip_data *data;
453 struct irq_desc *desc;
454 int irq, vector;
455
456
457 for_each_irq_desc(irq, desc) {
458 struct irq_data *idata = irq_desc_get_irq_data(desc);
459
460 data = apic_chip_data(idata);
461 if (!data || !cpumask_test_cpu(cpu, data->domain))
462 continue;
463 vector = data->cfg.vector;
464 per_cpu(vector_irq, cpu)[vector] = desc;
465 }
466
467 for (vector = 0; vector < NR_VECTORS; ++vector) {
468 desc = per_cpu(vector_irq, cpu)[vector];
469 if (IS_ERR_OR_NULL(desc))
470 continue;
471
472 data = apic_chip_data(irq_desc_get_irq_data(desc));
473 if (!cpumask_test_cpu(cpu, data->domain))
474 per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
475 }
476}
477
478
479
480
481void setup_vector_irq(int cpu)
482{
483 int irq;
484
485 lockdep_assert_held(&vector_lock);
486
487
488
489
490
491
492
493 for (irq = 0; irq < nr_legacy_irqs(); irq++)
494 per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq_to_desc(irq);
495
496 __setup_vector_irq(cpu);
497}
498
499static int apic_retrigger_irq(struct irq_data *irq_data)
500{
501 struct apic_chip_data *data = apic_chip_data(irq_data);
502 unsigned long flags;
503 int cpu;
504
505 raw_spin_lock_irqsave(&vector_lock, flags);
506 cpu = cpumask_first_and(data->domain, cpu_online_mask);
507 apic->send_IPI_mask(cpumask_of(cpu), data->cfg.vector);
508 raw_spin_unlock_irqrestore(&vector_lock, flags);
509
510 return 1;
511}
512
513void apic_ack_edge(struct irq_data *data)
514{
515 irq_complete_move(irqd_cfg(data));
516 irq_move_irq(data);
517 ack_APIC_irq();
518}
519
520static int apic_set_affinity(struct irq_data *irq_data,
521 const struct cpumask *dest, bool force)
522{
523 struct apic_chip_data *data = irq_data->chip_data;
524 int err, irq = irq_data->irq;
525
526 if (!config_enabled(CONFIG_SMP))
527 return -EPERM;
528
529 if (!cpumask_intersects(dest, cpu_online_mask))
530 return -EINVAL;
531
532 err = assign_irq_vector(irq, data, dest);
533 return err ? err : IRQ_SET_MASK_OK;
534}
535
536static struct irq_chip lapic_controller = {
537 .irq_ack = apic_ack_edge,
538 .irq_set_affinity = apic_set_affinity,
539 .irq_retrigger = apic_retrigger_irq,
540};
541
542#ifdef CONFIG_SMP
543static void __send_cleanup_vector(struct apic_chip_data *data)
544{
545 raw_spin_lock(&vector_lock);
546 cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
547 data->move_in_progress = 0;
548 if (!cpumask_empty(data->old_domain))
549 apic->send_IPI_mask(data->old_domain, IRQ_MOVE_CLEANUP_VECTOR);
550 raw_spin_unlock(&vector_lock);
551}
552
553void send_cleanup_vector(struct irq_cfg *cfg)
554{
555 struct apic_chip_data *data;
556
557 data = container_of(cfg, struct apic_chip_data, cfg);
558 if (data->move_in_progress)
559 __send_cleanup_vector(data);
560}
561
562asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
563{
564 unsigned vector, me;
565
566 entering_ack_irq();
567
568
569 raw_spin_lock(&vector_lock);
570
571 me = smp_processor_id();
572 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
573 struct apic_chip_data *data;
574 struct irq_desc *desc;
575 unsigned int irr;
576
577 retry:
578 desc = __this_cpu_read(vector_irq[vector]);
579 if (IS_ERR_OR_NULL(desc))
580 continue;
581
582 if (!raw_spin_trylock(&desc->lock)) {
583 raw_spin_unlock(&vector_lock);
584 cpu_relax();
585 raw_spin_lock(&vector_lock);
586 goto retry;
587 }
588
589 data = apic_chip_data(irq_desc_get_irq_data(desc));
590 if (!data)
591 goto unlock;
592
593
594
595
596
597 if (data->move_in_progress ||
598 !cpumask_test_cpu(me, data->old_domain))
599 goto unlock;
600
601
602
603
604
605
606
607
608
609
610
611
612
613 if (vector == data->cfg.vector &&
614 cpumask_test_cpu(me, data->domain))
615 goto unlock;
616
617 irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
618
619
620
621
622
623
624
625 if (irr & (1 << (vector % 32))) {
626 apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
627 goto unlock;
628 }
629 __this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
630 cpumask_clear_cpu(me, data->old_domain);
631unlock:
632 raw_spin_unlock(&desc->lock);
633 }
634
635 raw_spin_unlock(&vector_lock);
636
637 exiting_irq();
638}
639
640static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
641{
642 unsigned me;
643 struct apic_chip_data *data;
644
645 data = container_of(cfg, struct apic_chip_data, cfg);
646 if (likely(!data->move_in_progress))
647 return;
648
649 me = smp_processor_id();
650 if (vector == data->cfg.vector && cpumask_test_cpu(me, data->domain))
651 __send_cleanup_vector(data);
652}
653
654void irq_complete_move(struct irq_cfg *cfg)
655{
656 __irq_complete_move(cfg, ~get_irq_regs()->orig_ax);
657}
658
659
660
661
662void irq_force_complete_move(struct irq_desc *desc)
663{
664 struct irq_data *irqdata = irq_desc_get_irq_data(desc);
665 struct apic_chip_data *data = apic_chip_data(irqdata);
666 struct irq_cfg *cfg = data ? &data->cfg : NULL;
667 unsigned int cpu;
668
669 if (!cfg)
670 return;
671
672
673
674
675
676
677
678
679
680 raw_spin_lock(&vector_lock);
681
682
683
684
685 cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
686
687
688
689
690
691
692 if (!data->move_in_progress && cpumask_empty(data->old_domain)) {
693 raw_spin_unlock(&vector_lock);
694 return;
695 }
696
697
698
699
700
701
702
703
704
705 if (data->move_in_progress) {
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738 pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n",
739 irqdata->irq, cfg->old_vector);
740 }
741
742
743
744
745 for_each_cpu(cpu, data->old_domain)
746 per_cpu(vector_irq, cpu)[cfg->old_vector] = VECTOR_UNUSED;
747
748
749 cpumask_clear(data->old_domain);
750 data->move_in_progress = 0;
751 raw_spin_unlock(&vector_lock);
752}
753#endif
754
755static void __init print_APIC_field(int base)
756{
757 int i;
758
759 printk(KERN_DEBUG);
760
761 for (i = 0; i < 8; i++)
762 pr_cont("%08x", apic_read(base + i*0x10));
763
764 pr_cont("\n");
765}
766
767static void __init print_local_APIC(void *dummy)
768{
769 unsigned int i, v, ver, maxlvt;
770 u64 icr;
771
772 pr_debug("printing local APIC contents on CPU#%d/%d:\n",
773 smp_processor_id(), hard_smp_processor_id());
774 v = apic_read(APIC_ID);
775 pr_info("... APIC ID: %08x (%01x)\n", v, read_apic_id());
776 v = apic_read(APIC_LVR);
777 pr_info("... APIC VERSION: %08x\n", v);
778 ver = GET_APIC_VERSION(v);
779 maxlvt = lapic_get_maxlvt();
780
781 v = apic_read(APIC_TASKPRI);
782 pr_debug("... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
783
784
785 if (APIC_INTEGRATED(ver)) {
786 if (!APIC_XAPIC(ver)) {
787 v = apic_read(APIC_ARBPRI);
788 pr_debug("... APIC ARBPRI: %08x (%02x)\n",
789 v, v & APIC_ARBPRI_MASK);
790 }
791 v = apic_read(APIC_PROCPRI);
792 pr_debug("... APIC PROCPRI: %08x\n", v);
793 }
794
795
796
797
798
799 if (!APIC_INTEGRATED(ver) || maxlvt == 3) {
800 v = apic_read(APIC_RRR);
801 pr_debug("... APIC RRR: %08x\n", v);
802 }
803
804 v = apic_read(APIC_LDR);
805 pr_debug("... APIC LDR: %08x\n", v);
806 if (!x2apic_enabled()) {
807 v = apic_read(APIC_DFR);
808 pr_debug("... APIC DFR: %08x\n", v);
809 }
810 v = apic_read(APIC_SPIV);
811 pr_debug("... APIC SPIV: %08x\n", v);
812
813 pr_debug("... APIC ISR field:\n");
814 print_APIC_field(APIC_ISR);
815 pr_debug("... APIC TMR field:\n");
816 print_APIC_field(APIC_TMR);
817 pr_debug("... APIC IRR field:\n");
818 print_APIC_field(APIC_IRR);
819
820
821 if (APIC_INTEGRATED(ver)) {
822
823 if (maxlvt > 3)
824 apic_write(APIC_ESR, 0);
825
826 v = apic_read(APIC_ESR);
827 pr_debug("... APIC ESR: %08x\n", v);
828 }
829
830 icr = apic_icr_read();
831 pr_debug("... APIC ICR: %08x\n", (u32)icr);
832 pr_debug("... APIC ICR2: %08x\n", (u32)(icr >> 32));
833
834 v = apic_read(APIC_LVTT);
835 pr_debug("... APIC LVTT: %08x\n", v);
836
837 if (maxlvt > 3) {
838
839 v = apic_read(APIC_LVTPC);
840 pr_debug("... APIC LVTPC: %08x\n", v);
841 }
842 v = apic_read(APIC_LVT0);
843 pr_debug("... APIC LVT0: %08x\n", v);
844 v = apic_read(APIC_LVT1);
845 pr_debug("... APIC LVT1: %08x\n", v);
846
847 if (maxlvt > 2) {
848
849 v = apic_read(APIC_LVTERR);
850 pr_debug("... APIC LVTERR: %08x\n", v);
851 }
852
853 v = apic_read(APIC_TMICT);
854 pr_debug("... APIC TMICT: %08x\n", v);
855 v = apic_read(APIC_TMCCT);
856 pr_debug("... APIC TMCCT: %08x\n", v);
857 v = apic_read(APIC_TDCR);
858 pr_debug("... APIC TDCR: %08x\n", v);
859
860 if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
861 v = apic_read(APIC_EFEAT);
862 maxlvt = (v >> 16) & 0xff;
863 pr_debug("... APIC EFEAT: %08x\n", v);
864 v = apic_read(APIC_ECTRL);
865 pr_debug("... APIC ECTRL: %08x\n", v);
866 for (i = 0; i < maxlvt; i++) {
867 v = apic_read(APIC_EILVTn(i));
868 pr_debug("... APIC EILVT%d: %08x\n", i, v);
869 }
870 }
871 pr_cont("\n");
872}
873
874static void __init print_local_APICs(int maxcpu)
875{
876 int cpu;
877
878 if (!maxcpu)
879 return;
880
881 preempt_disable();
882 for_each_online_cpu(cpu) {
883 if (cpu >= maxcpu)
884 break;
885 smp_call_function_single(cpu, print_local_APIC, NULL, 1);
886 }
887 preempt_enable();
888}
889
890static void __init print_PIC(void)
891{
892 unsigned int v;
893 unsigned long flags;
894
895 if (!nr_legacy_irqs())
896 return;
897
898 pr_debug("\nprinting PIC contents\n");
899
900 raw_spin_lock_irqsave(&i8259A_lock, flags);
901
902 v = inb(0xa1) << 8 | inb(0x21);
903 pr_debug("... PIC IMR: %04x\n", v);
904
905 v = inb(0xa0) << 8 | inb(0x20);
906 pr_debug("... PIC IRR: %04x\n", v);
907
908 outb(0x0b, 0xa0);
909 outb(0x0b, 0x20);
910 v = inb(0xa0) << 8 | inb(0x20);
911 outb(0x0a, 0xa0);
912 outb(0x0a, 0x20);
913
914 raw_spin_unlock_irqrestore(&i8259A_lock, flags);
915
916 pr_debug("... PIC ISR: %04x\n", v);
917
918 v = inb(0x4d1) << 8 | inb(0x4d0);
919 pr_debug("... PIC ELCR: %04x\n", v);
920}
921
922static int show_lapic __initdata = 1;
923static __init int setup_show_lapic(char *arg)
924{
925 int num = -1;
926
927 if (strcmp(arg, "all") == 0) {
928 show_lapic = CONFIG_NR_CPUS;
929 } else {
930 get_option(&arg, &num);
931 if (num >= 0)
932 show_lapic = num;
933 }
934
935 return 1;
936}
937__setup("show_lapic=", setup_show_lapic);
938
939static int __init print_ICs(void)
940{
941 if (apic_verbosity == APIC_QUIET)
942 return 0;
943
944 print_PIC();
945
946
947 if (!boot_cpu_has(X86_FEATURE_APIC) && !apic_from_smp_config())
948 return 0;
949
950 print_local_APICs(show_lapic);
951 print_IO_APICs();
952
953 return 0;
954}
955
956late_initcall(print_ICs);
957