diff options
Diffstat (limited to 'arch/x86_64/kernel/apic.c')
-rw-r--r-- | arch/x86_64/kernel/apic.c | 104 |
1 files changed, 97 insertions, 7 deletions
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 4d9d5ed942b2..124b2d27b4ac 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/kernel_stat.h> | 25 | #include <linux/kernel_stat.h> |
26 | #include <linux/sysdev.h> | 26 | #include <linux/sysdev.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/ioport.h> | ||
28 | 29 | ||
29 | #include <asm/atomic.h> | 30 | #include <asm/atomic.h> |
30 | #include <asm/smp.h> | 31 | #include <asm/smp.h> |
@@ -45,6 +46,12 @@ int apic_calibrate_pmtmr __initdata; | |||
45 | 46 | ||
46 | int disable_apic_timer __initdata; | 47 | int disable_apic_timer __initdata; |
47 | 48 | ||
49 | static struct resource *ioapic_resources; | ||
50 | static struct resource lapic_resource = { | ||
51 | .name = "Local APIC", | ||
52 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, | ||
53 | }; | ||
54 | |||
48 | /* | 55 | /* |
49 | * cpu_mask that denotes the CPUs that needs timer interrupt coming in as | 56 | * cpu_mask that denotes the CPUs that needs timer interrupt coming in as |
50 | * IPIs in place of local APIC timers | 57 | * IPIs in place of local APIC timers |
@@ -133,7 +140,6 @@ void clear_local_APIC(void) | |||
133 | apic_write(APIC_LVTERR, APIC_LVT_MASKED); | 140 | apic_write(APIC_LVTERR, APIC_LVT_MASKED); |
134 | if (maxlvt >= 4) | 141 | if (maxlvt >= 4) |
135 | apic_write(APIC_LVTPC, APIC_LVT_MASKED); | 142 | apic_write(APIC_LVTPC, APIC_LVT_MASKED); |
136 | v = GET_APIC_VERSION(apic_read(APIC_LVR)); | ||
137 | apic_write(APIC_ESR, 0); | 143 | apic_write(APIC_ESR, 0); |
138 | apic_read(APIC_ESR); | 144 | apic_read(APIC_ESR); |
139 | } | 145 | } |
@@ -452,23 +458,30 @@ static struct { | |||
452 | static int lapic_suspend(struct sys_device *dev, pm_message_t state) | 458 | static int lapic_suspend(struct sys_device *dev, pm_message_t state) |
453 | { | 459 | { |
454 | unsigned long flags; | 460 | unsigned long flags; |
461 | int maxlvt; | ||
455 | 462 | ||
456 | if (!apic_pm_state.active) | 463 | if (!apic_pm_state.active) |
457 | return 0; | 464 | return 0; |
458 | 465 | ||
466 | maxlvt = get_maxlvt(); | ||
467 | |||
459 | apic_pm_state.apic_id = apic_read(APIC_ID); | 468 | apic_pm_state.apic_id = apic_read(APIC_ID); |
460 | apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); | 469 | apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); |
461 | apic_pm_state.apic_ldr = apic_read(APIC_LDR); | 470 | apic_pm_state.apic_ldr = apic_read(APIC_LDR); |
462 | apic_pm_state.apic_dfr = apic_read(APIC_DFR); | 471 | apic_pm_state.apic_dfr = apic_read(APIC_DFR); |
463 | apic_pm_state.apic_spiv = apic_read(APIC_SPIV); | 472 | apic_pm_state.apic_spiv = apic_read(APIC_SPIV); |
464 | apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); | 473 | apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); |
465 | apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); | 474 | if (maxlvt >= 4) |
475 | apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); | ||
466 | apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0); | 476 | apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0); |
467 | apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1); | 477 | apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1); |
468 | apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); | 478 | apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); |
469 | apic_pm_state.apic_tmict = apic_read(APIC_TMICT); | 479 | apic_pm_state.apic_tmict = apic_read(APIC_TMICT); |
470 | apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); | 480 | apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); |
471 | apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); | 481 | #ifdef CONFIG_X86_MCE_INTEL |
482 | if (maxlvt >= 5) | ||
483 | apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); | ||
484 | #endif | ||
472 | local_irq_save(flags); | 485 | local_irq_save(flags); |
473 | disable_local_APIC(); | 486 | disable_local_APIC(); |
474 | local_irq_restore(flags); | 487 | local_irq_restore(flags); |
@@ -479,10 +492,13 @@ static int lapic_resume(struct sys_device *dev) | |||
479 | { | 492 | { |
480 | unsigned int l, h; | 493 | unsigned int l, h; |
481 | unsigned long flags; | 494 | unsigned long flags; |
495 | int maxlvt; | ||
482 | 496 | ||
483 | if (!apic_pm_state.active) | 497 | if (!apic_pm_state.active) |
484 | return 0; | 498 | return 0; |
485 | 499 | ||
500 | maxlvt = get_maxlvt(); | ||
501 | |||
486 | local_irq_save(flags); | 502 | local_irq_save(flags); |
487 | rdmsr(MSR_IA32_APICBASE, l, h); | 503 | rdmsr(MSR_IA32_APICBASE, l, h); |
488 | l &= ~MSR_IA32_APICBASE_BASE; | 504 | l &= ~MSR_IA32_APICBASE_BASE; |
@@ -496,8 +512,12 @@ static int lapic_resume(struct sys_device *dev) | |||
496 | apic_write(APIC_SPIV, apic_pm_state.apic_spiv); | 512 | apic_write(APIC_SPIV, apic_pm_state.apic_spiv); |
497 | apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); | 513 | apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); |
498 | apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); | 514 | apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); |
499 | apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); | 515 | #ifdef CONFIG_X86_MCE_INTEL |
500 | apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); | 516 | if (maxlvt >= 5) |
517 | apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); | ||
518 | #endif | ||
519 | if (maxlvt >= 4) | ||
520 | apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); | ||
501 | apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); | 521 | apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); |
502 | apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); | 522 | apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); |
503 | apic_write(APIC_TMICT, apic_pm_state.apic_tmict); | 523 | apic_write(APIC_TMICT, apic_pm_state.apic_tmict); |
@@ -585,6 +605,64 @@ static int __init detect_init_APIC (void) | |||
585 | return 0; | 605 | return 0; |
586 | } | 606 | } |
587 | 607 | ||
608 | #ifdef CONFIG_X86_IO_APIC | ||
609 | static struct resource * __init ioapic_setup_resources(void) | ||
610 | { | ||
611 | #define IOAPIC_RESOURCE_NAME_SIZE 11 | ||
612 | unsigned long n; | ||
613 | struct resource *res; | ||
614 | char *mem; | ||
615 | int i; | ||
616 | |||
617 | if (nr_ioapics <= 0) | ||
618 | return NULL; | ||
619 | |||
620 | n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource); | ||
621 | n *= nr_ioapics; | ||
622 | |||
623 | mem = alloc_bootmem(n); | ||
624 | res = (void *)mem; | ||
625 | |||
626 | if (mem != NULL) { | ||
627 | memset(mem, 0, n); | ||
628 | mem += sizeof(struct resource) * nr_ioapics; | ||
629 | |||
630 | for (i = 0; i < nr_ioapics; i++) { | ||
631 | res[i].name = mem; | ||
632 | res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
633 | sprintf(mem, "IOAPIC %u", i); | ||
634 | mem += IOAPIC_RESOURCE_NAME_SIZE; | ||
635 | } | ||
636 | } | ||
637 | |||
638 | ioapic_resources = res; | ||
639 | |||
640 | return res; | ||
641 | } | ||
642 | |||
643 | static int __init ioapic_insert_resources(void) | ||
644 | { | ||
645 | int i; | ||
646 | struct resource *r = ioapic_resources; | ||
647 | |||
648 | if (!r) { | ||
649 | printk("IO APIC resources could be not be allocated.\n"); | ||
650 | return -1; | ||
651 | } | ||
652 | |||
653 | for (i = 0; i < nr_ioapics; i++) { | ||
654 | insert_resource(&iomem_resource, r); | ||
655 | r++; | ||
656 | } | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | /* Insert the IO APIC resources after PCI initialization has occured to handle | ||
662 | * IO APICS that are mapped in on a BAR in PCI space. */ | ||
663 | late_initcall(ioapic_insert_resources); | ||
664 | #endif | ||
665 | |||
588 | void __init init_apic_mappings(void) | 666 | void __init init_apic_mappings(void) |
589 | { | 667 | { |
590 | unsigned long apic_phys; | 668 | unsigned long apic_phys; |
@@ -604,6 +682,11 @@ void __init init_apic_mappings(void) | |||
604 | apic_mapped = 1; | 682 | apic_mapped = 1; |
605 | apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys); | 683 | apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys); |
606 | 684 | ||
685 | /* Put local APIC into the resource map. */ | ||
686 | lapic_resource.start = apic_phys; | ||
687 | lapic_resource.end = lapic_resource.start + PAGE_SIZE - 1; | ||
688 | insert_resource(&iomem_resource, &lapic_resource); | ||
689 | |||
607 | /* | 690 | /* |
608 | * Fetch the APIC ID of the BSP in case we have a | 691 | * Fetch the APIC ID of the BSP in case we have a |
609 | * default configuration (or the MP table is broken). | 692 | * default configuration (or the MP table is broken). |
@@ -613,7 +696,9 @@ void __init init_apic_mappings(void) | |||
613 | { | 696 | { |
614 | unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; | 697 | unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; |
615 | int i; | 698 | int i; |
699 | struct resource *ioapic_res; | ||
616 | 700 | ||
701 | ioapic_res = ioapic_setup_resources(); | ||
617 | for (i = 0; i < nr_ioapics; i++) { | 702 | for (i = 0; i < nr_ioapics; i++) { |
618 | if (smp_found_config) { | 703 | if (smp_found_config) { |
619 | ioapic_phys = mp_ioapics[i].mpc_apicaddr; | 704 | ioapic_phys = mp_ioapics[i].mpc_apicaddr; |
@@ -625,6 +710,12 @@ void __init init_apic_mappings(void) | |||
625 | apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n", | 710 | apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n", |
626 | __fix_to_virt(idx), ioapic_phys); | 711 | __fix_to_virt(idx), ioapic_phys); |
627 | idx++; | 712 | idx++; |
713 | |||
714 | if (ioapic_res != NULL) { | ||
715 | ioapic_res->start = ioapic_phys; | ||
716 | ioapic_res->end = ioapic_phys + (4 * 1024) - 1; | ||
717 | ioapic_res++; | ||
718 | } | ||
628 | } | 719 | } |
629 | } | 720 | } |
630 | } | 721 | } |
@@ -644,10 +735,9 @@ void __init init_apic_mappings(void) | |||
644 | 735 | ||
645 | static void __setup_APIC_LVTT(unsigned int clocks) | 736 | static void __setup_APIC_LVTT(unsigned int clocks) |
646 | { | 737 | { |
647 | unsigned int lvtt_value, tmp_value, ver; | 738 | unsigned int lvtt_value, tmp_value; |
648 | int cpu = smp_processor_id(); | 739 | int cpu = smp_processor_id(); |
649 | 740 | ||
650 | ver = GET_APIC_VERSION(apic_read(APIC_LVR)); | ||
651 | lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; | 741 | lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; |
652 | 742 | ||
653 | if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) | 743 | if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) |