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 (!IS_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 __irq_entry 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;
665 struct apic_chip_data *data;
666 struct irq_cfg *cfg;
667 unsigned int cpu;
668
669
670
671
672
673
674
675
676
677
678 irqdata = irq_domain_get_irq_data(x86_vector_domain,
679 irq_desc_get_irq(desc));
680 if (!irqdata)
681 return;
682
683 data = apic_chip_data(irqdata);
684 cfg = data ? &data->cfg : NULL;
685
686 if (!cfg)
687 return;
688
689
690
691
692
693
694
695
696
697 raw_spin_lock(&vector_lock);
698
699
700
701
702 cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
703
704
705
706
707
708
709 if (!data->move_in_progress && cpumask_empty(data->old_domain)) {
710 raw_spin_unlock(&vector_lock);
711 return;
712 }
713
714
715
716
717
718
719
720
721
722 if (data->move_in_progress) {
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755 pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n",
756 irqdata->irq, cfg->old_vector);
757 }
758
759
760
761
762 for_each_cpu(cpu, data->old_domain)
763 per_cpu(vector_irq, cpu)[cfg->old_vector] = VECTOR_UNUSED;
764
765
766 cpumask_clear(data->old_domain);
767 data->move_in_progress = 0;
768 raw_spin_unlock(&vector_lock);
769}
770#endif
771
772static void __init print_APIC_field(int base)
773{
774 int i;
775
776 printk(KERN_DEBUG);
777
778 for (i = 0; i < 8; i++)
779 pr_cont("%08x", apic_read(base + i*0x10));
780
781 pr_cont("\n");
782}
783
784static void __init print_local_APIC(void *dummy)
785{
786 unsigned int i, v, ver, maxlvt;
787 u64 icr;
788
789 pr_debug("printing local APIC contents on CPU#%d/%d:\n",
790 smp_processor_id(), hard_smp_processor_id());
791 v = apic_read(APIC_ID);
792 pr_info("... APIC ID: %08x (%01x)\n", v, read_apic_id());
793 v = apic_read(APIC_LVR);
794 pr_info("... APIC VERSION: %08x\n", v);
795 ver = GET_APIC_VERSION(v);
796 maxlvt = lapic_get_maxlvt();
797
798 v = apic_read(APIC_TASKPRI);
799 pr_debug("... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
800
801
802 if (APIC_INTEGRATED(ver)) {
803 if (!APIC_XAPIC(ver)) {
804 v = apic_read(APIC_ARBPRI);
805 pr_debug("... APIC ARBPRI: %08x (%02x)\n",
806 v, v & APIC_ARBPRI_MASK);
807 }
808 v = apic_read(APIC_PROCPRI);
809 pr_debug("... APIC PROCPRI: %08x\n", v);
810 }
811
812
813
814
815
816 if (!APIC_INTEGRATED(ver) || maxlvt == 3) {
817 v = apic_read(APIC_RRR);
818 pr_debug("... APIC RRR: %08x\n", v);
819 }
820
821 v = apic_read(APIC_LDR);
822 pr_debug("... APIC LDR: %08x\n", v);
823 if (!x2apic_enabled()) {
824 v = apic_read(APIC_DFR);
825 pr_debug("... APIC DFR: %08x\n", v);
826 }
827 v = apic_read(APIC_SPIV);
828 pr_debug("... APIC SPIV: %08x\n", v);
829
830 pr_debug("... APIC ISR field:\n");
831 print_APIC_field(APIC_ISR);
832 pr_debug("... APIC TMR field:\n");
833 print_APIC_field(APIC_TMR);
834 pr_debug("... APIC IRR field:\n");
835 print_APIC_field(APIC_IRR);
836
837
838 if (APIC_INTEGRATED(ver)) {
839
840 if (maxlvt > 3)
841 apic_write(APIC_ESR, 0);
842
843 v = apic_read(APIC_ESR);
844 pr_debug("... APIC ESR: %08x\n", v);
845 }
846
847 icr = apic_icr_read();
848 pr_debug("... APIC ICR: %08x\n", (u32)icr);
849 pr_debug("... APIC ICR2: %08x\n", (u32)(icr >> 32));
850
851 v = apic_read(APIC_LVTT);
852 pr_debug("... APIC LVTT: %08x\n", v);
853
854 if (maxlvt > 3) {
855
856 v = apic_read(APIC_LVTPC);
857 pr_debug("... APIC LVTPC: %08x\n", v);
858 }
859 v = apic_read(APIC_LVT0);
860 pr_debug("... APIC LVT0: %08x\n", v);
861 v = apic_read(APIC_LVT1);
862 pr_debug("... APIC LVT1: %08x\n", v);
863
864 if (maxlvt > 2) {
865
866 v = apic_read(APIC_LVTERR);
867 pr_debug("... APIC LVTERR: %08x\n", v);
868 }
869
870 v = apic_read(APIC_TMICT);
871 pr_debug("... APIC TMICT: %08x\n", v);
872 v = apic_read(APIC_TMCCT);
873 pr_debug("... APIC TMCCT: %08x\n", v);
874 v = apic_read(APIC_TDCR);
875 pr_debug("... APIC TDCR: %08x\n", v);
876
877 if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
878 v = apic_read(APIC_EFEAT);
879 maxlvt = (v >> 16) & 0xff;
880 pr_debug("... APIC EFEAT: %08x\n", v);
881 v = apic_read(APIC_ECTRL);
882 pr_debug("... APIC ECTRL: %08x\n", v);
883 for (i = 0; i < maxlvt; i++) {
884 v = apic_read(APIC_EILVTn(i));
885 pr_debug("... APIC EILVT%d: %08x\n", i, v);
886 }
887 }
888 pr_cont("\n");
889}
890
891static void __init print_local_APICs(int maxcpu)
892{
893 int cpu;
894
895 if (!maxcpu)
896 return;
897
898 preempt_disable();
899 for_each_online_cpu(cpu) {
900 if (cpu >= maxcpu)
901 break;
902 smp_call_function_single(cpu, print_local_APIC, NULL, 1);
903 }
904 preempt_enable();
905}
906
907static void __init print_PIC(void)
908{
909 unsigned int v;
910 unsigned long flags;
911
912 if (!nr_legacy_irqs())
913 return;
914
915 pr_debug("\nprinting PIC contents\n");
916
917 raw_spin_lock_irqsave(&i8259A_lock, flags);
918
919 v = inb(0xa1) << 8 | inb(0x21);
920 pr_debug("... PIC IMR: %04x\n", v);
921
922 v = inb(0xa0) << 8 | inb(0x20);
923 pr_debug("... PIC IRR: %04x\n", v);
924
925 outb(0x0b, 0xa0);
926 outb(0x0b, 0x20);
927 v = inb(0xa0) << 8 | inb(0x20);
928 outb(0x0a, 0xa0);
929 outb(0x0a, 0x20);
930
931 raw_spin_unlock_irqrestore(&i8259A_lock, flags);
932
933 pr_debug("... PIC ISR: %04x\n", v);
934
935 v = inb(0x4d1) << 8 | inb(0x4d0);
936 pr_debug("... PIC ELCR: %04x\n", v);
937}
938
939static int show_lapic __initdata = 1;
940static __init int setup_show_lapic(char *arg)
941{
942 int num = -1;
943
944 if (strcmp(arg, "all") == 0) {
945 show_lapic = CONFIG_NR_CPUS;
946 } else {
947 get_option(&arg, &num);
948 if (num >= 0)
949 show_lapic = num;
950 }
951
952 return 1;
953}
954__setup("show_lapic=", setup_show_lapic);
955
956static int __init print_ICs(void)
957{
958 if (apic_verbosity == APIC_QUIET)
959 return 0;
960
961 print_PIC();
962
963
964 if (!boot_cpu_has(X86_FEATURE_APIC) && !apic_from_smp_config())
965 return 0;
966
967 print_local_APICs(show_lapic);
968 print_IO_APICs();
969
970 return 0;
971}
972
973late_initcall(print_ICs);
974