diff options
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 52fa56399a50..f98d84caf94c 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -186,7 +186,7 @@ static struct resource lapic_resource = { | |||
186 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, | 186 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, |
187 | }; | 187 | }; |
188 | 188 | ||
189 | static unsigned int calibration_result; | 189 | unsigned int lapic_timer_frequency = 0; |
190 | 190 | ||
191 | static void apic_pm_activate(void); | 191 | static void apic_pm_activate(void); |
192 | 192 | ||
@@ -454,7 +454,7 @@ static void lapic_timer_setup(enum clock_event_mode mode, | |||
454 | switch (mode) { | 454 | switch (mode) { |
455 | case CLOCK_EVT_MODE_PERIODIC: | 455 | case CLOCK_EVT_MODE_PERIODIC: |
456 | case CLOCK_EVT_MODE_ONESHOT: | 456 | case CLOCK_EVT_MODE_ONESHOT: |
457 | __setup_APIC_LVTT(calibration_result, | 457 | __setup_APIC_LVTT(lapic_timer_frequency, |
458 | mode != CLOCK_EVT_MODE_PERIODIC, 1); | 458 | mode != CLOCK_EVT_MODE_PERIODIC, 1); |
459 | break; | 459 | break; |
460 | case CLOCK_EVT_MODE_UNUSED: | 460 | case CLOCK_EVT_MODE_UNUSED: |
@@ -638,6 +638,25 @@ static int __init calibrate_APIC_clock(void) | |||
638 | long delta, deltatsc; | 638 | long delta, deltatsc; |
639 | int pm_referenced = 0; | 639 | int pm_referenced = 0; |
640 | 640 | ||
641 | /** | ||
642 | * check if lapic timer has already been calibrated by platform | ||
643 | * specific routine, such as tsc calibration code. if so, we just fill | ||
644 | * in the clockevent structure and return. | ||
645 | */ | ||
646 | |||
647 | if (lapic_timer_frequency) { | ||
648 | apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n", | ||
649 | lapic_timer_frequency); | ||
650 | lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR, | ||
651 | TICK_NSEC, lapic_clockevent.shift); | ||
652 | lapic_clockevent.max_delta_ns = | ||
653 | clockevent_delta2ns(0x7FFFFF, &lapic_clockevent); | ||
654 | lapic_clockevent.min_delta_ns = | ||
655 | clockevent_delta2ns(0xF, &lapic_clockevent); | ||
656 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; | ||
657 | return 0; | ||
658 | } | ||
659 | |||
641 | local_irq_disable(); | 660 | local_irq_disable(); |
642 | 661 | ||
643 | /* Replace the global interrupt handler */ | 662 | /* Replace the global interrupt handler */ |
@@ -679,12 +698,12 @@ static int __init calibrate_APIC_clock(void) | |||
679 | lapic_clockevent.min_delta_ns = | 698 | lapic_clockevent.min_delta_ns = |
680 | clockevent_delta2ns(0xF, &lapic_clockevent); | 699 | clockevent_delta2ns(0xF, &lapic_clockevent); |
681 | 700 | ||
682 | calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS; | 701 | lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS; |
683 | 702 | ||
684 | apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta); | 703 | apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta); |
685 | apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult); | 704 | apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult); |
686 | apic_printk(APIC_VERBOSE, "..... calibration result: %u\n", | 705 | apic_printk(APIC_VERBOSE, "..... calibration result: %u\n", |
687 | calibration_result); | 706 | lapic_timer_frequency); |
688 | 707 | ||
689 | if (cpu_has_tsc) { | 708 | if (cpu_has_tsc) { |
690 | apic_printk(APIC_VERBOSE, "..... CPU clock speed is " | 709 | apic_printk(APIC_VERBOSE, "..... CPU clock speed is " |
@@ -695,13 +714,13 @@ static int __init calibrate_APIC_clock(void) | |||
695 | 714 | ||
696 | apic_printk(APIC_VERBOSE, "..... host bus clock speed is " | 715 | apic_printk(APIC_VERBOSE, "..... host bus clock speed is " |
697 | "%u.%04u MHz.\n", | 716 | "%u.%04u MHz.\n", |
698 | calibration_result / (1000000 / HZ), | 717 | lapic_timer_frequency / (1000000 / HZ), |
699 | calibration_result % (1000000 / HZ)); | 718 | lapic_timer_frequency % (1000000 / HZ)); |
700 | 719 | ||
701 | /* | 720 | /* |
702 | * Do a sanity check on the APIC calibration result | 721 | * Do a sanity check on the APIC calibration result |
703 | */ | 722 | */ |
704 | if (calibration_result < (1000000 / HZ)) { | 723 | if (lapic_timer_frequency < (1000000 / HZ)) { |
705 | local_irq_enable(); | 724 | local_irq_enable(); |
706 | pr_warning("APIC frequency too slow, disabling apic timer\n"); | 725 | pr_warning("APIC frequency too slow, disabling apic timer\n"); |
707 | return -1; | 726 | return -1; |
@@ -1437,27 +1456,21 @@ void enable_x2apic(void) | |||
1437 | 1456 | ||
1438 | int __init enable_IR(void) | 1457 | int __init enable_IR(void) |
1439 | { | 1458 | { |
1440 | #ifdef CONFIG_INTR_REMAP | 1459 | #ifdef CONFIG_IRQ_REMAP |
1441 | if (!intr_remapping_supported()) { | 1460 | if (!intr_remapping_supported()) { |
1442 | pr_debug("intr-remapping not supported\n"); | 1461 | pr_debug("intr-remapping not supported\n"); |
1443 | return 0; | 1462 | return -1; |
1444 | } | 1463 | } |
1445 | 1464 | ||
1446 | if (!x2apic_preenabled && skip_ioapic_setup) { | 1465 | if (!x2apic_preenabled && skip_ioapic_setup) { |
1447 | pr_info("Skipped enabling intr-remap because of skipping " | 1466 | pr_info("Skipped enabling intr-remap because of skipping " |
1448 | "io-apic setup\n"); | 1467 | "io-apic setup\n"); |
1449 | return 0; | 1468 | return -1; |
1450 | } | 1469 | } |
1451 | 1470 | ||
1452 | if (enable_intr_remapping(x2apic_supported())) | 1471 | return enable_intr_remapping(); |
1453 | return 0; | ||
1454 | |||
1455 | pr_info("Enabled Interrupt-remapping\n"); | ||
1456 | |||
1457 | return 1; | ||
1458 | |||
1459 | #endif | 1472 | #endif |
1460 | return 0; | 1473 | return -1; |
1461 | } | 1474 | } |
1462 | 1475 | ||
1463 | void __init enable_IR_x2apic(void) | 1476 | void __init enable_IR_x2apic(void) |
@@ -1481,11 +1494,11 @@ void __init enable_IR_x2apic(void) | |||
1481 | mask_ioapic_entries(); | 1494 | mask_ioapic_entries(); |
1482 | 1495 | ||
1483 | if (dmar_table_init_ret) | 1496 | if (dmar_table_init_ret) |
1484 | ret = 0; | 1497 | ret = -1; |
1485 | else | 1498 | else |
1486 | ret = enable_IR(); | 1499 | ret = enable_IR(); |
1487 | 1500 | ||
1488 | if (!ret) { | 1501 | if (ret < 0) { |
1489 | /* IR is required if there is APIC ID > 255 even when running | 1502 | /* IR is required if there is APIC ID > 255 even when running |
1490 | * under KVM | 1503 | * under KVM |
1491 | */ | 1504 | */ |
@@ -1499,6 +1512,9 @@ void __init enable_IR_x2apic(void) | |||
1499 | x2apic_force_phys(); | 1512 | x2apic_force_phys(); |
1500 | } | 1513 | } |
1501 | 1514 | ||
1515 | if (ret == IRQ_REMAP_XAPIC_MODE) | ||
1516 | goto nox2apic; | ||
1517 | |||
1502 | x2apic_enabled = 1; | 1518 | x2apic_enabled = 1; |
1503 | 1519 | ||
1504 | if (x2apic_supported() && !x2apic_mode) { | 1520 | if (x2apic_supported() && !x2apic_mode) { |
@@ -1508,19 +1524,21 @@ void __init enable_IR_x2apic(void) | |||
1508 | } | 1524 | } |
1509 | 1525 | ||
1510 | nox2apic: | 1526 | nox2apic: |
1511 | if (!ret) /* IR enabling failed */ | 1527 | if (ret < 0) /* IR enabling failed */ |
1512 | restore_ioapic_entries(); | 1528 | restore_ioapic_entries(); |
1513 | legacy_pic->restore_mask(); | 1529 | legacy_pic->restore_mask(); |
1514 | local_irq_restore(flags); | 1530 | local_irq_restore(flags); |
1515 | 1531 | ||
1516 | out: | 1532 | out: |
1517 | if (x2apic_enabled) | 1533 | if (x2apic_enabled || !x2apic_supported()) |
1518 | return; | 1534 | return; |
1519 | 1535 | ||
1520 | if (x2apic_preenabled) | 1536 | if (x2apic_preenabled) |
1521 | panic("x2apic: enabled by BIOS but kernel init failed."); | 1537 | panic("x2apic: enabled by BIOS but kernel init failed."); |
1522 | else if (cpu_has_x2apic) | 1538 | else if (ret == IRQ_REMAP_XAPIC_MODE) |
1523 | pr_info("Not enabling x2apic, Intr-remapping init failed.\n"); | 1539 | pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n"); |
1540 | else if (ret < 0) | ||
1541 | pr_info("x2apic not enabled, IRQ remapping init failed\n"); | ||
1524 | } | 1542 | } |
1525 | 1543 | ||
1526 | #ifdef CONFIG_X86_64 | 1544 | #ifdef CONFIG_X86_64 |