diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2009-08-04 15:07:09 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2009-08-27 17:33:20 -0400 |
commit | c8bc6f3c806f1fcbfdbf0b1ff6c52dba59192d3b (patch) | |
tree | 072f772308c44eb0223fbfb45c8a055918c70502 | |
parent | 20f3097bfe5fb5ced0b14f9ea2620c4039bf1dde (diff) |
x86: arch specific support for remapping HPET MSIs
x86 arch support for remapping HPET MSI's by associating the HPET timer block
with the interrupt-remapping HW unit and setting up appropriate irq_chip
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Jay Fenlason <fenlason@redhat.com>
LKML-Reference: <20090804190729.630510000@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/include/asm/hpet.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/boot.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 49 | ||||
-rw-r--r-- | arch/x86/kernel/hpet.c | 3 |
4 files changed, 47 insertions, 11 deletions
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h index 65847c578b70..5d89fd2a3690 100644 --- a/arch/x86/include/asm/hpet.h +++ b/arch/x86/include/asm/hpet.h | |||
@@ -65,6 +65,7 @@ | |||
65 | /* hpet memory map physical address */ | 65 | /* hpet memory map physical address */ |
66 | extern unsigned long hpet_address; | 66 | extern unsigned long hpet_address; |
67 | extern unsigned long force_hpet_address; | 67 | extern unsigned long force_hpet_address; |
68 | extern u8 hpet_blockid; | ||
68 | extern int hpet_force_user; | 69 | extern int hpet_force_user; |
69 | extern int is_hpet_enabled(void); | 70 | extern int is_hpet_enabled(void); |
70 | extern int hpet_enable(void); | 71 | extern int hpet_enable(void); |
@@ -78,9 +79,9 @@ extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg); | |||
78 | extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg); | 79 | extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg); |
79 | 80 | ||
80 | #ifdef CONFIG_PCI_MSI | 81 | #ifdef CONFIG_PCI_MSI |
81 | extern int arch_setup_hpet_msi(unsigned int irq); | 82 | extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id); |
82 | #else | 83 | #else |
83 | static inline int arch_setup_hpet_msi(unsigned int irq) | 84 | static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id) |
84 | { | 85 | { |
85 | return -EINVAL; | 86 | return -EINVAL; |
86 | } | 87 | } |
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 6b8ca3a0285d..eae642b0f345 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -624,6 +624,7 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table) | |||
624 | } | 624 | } |
625 | 625 | ||
626 | hpet_address = hpet_tbl->address.address; | 626 | hpet_address = hpet_tbl->address.address; |
627 | hpet_blockid = hpet_tbl->sequence; | ||
627 | 628 | ||
628 | /* | 629 | /* |
629 | * Some broken BIOSes advertise HPET at 0x0. We really do not | 630 | * Some broken BIOSes advertise HPET at 0x0. We really do not |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index d2ed6c5ddc80..d9c6f14d3b32 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -3254,7 +3254,8 @@ void destroy_irq(unsigned int irq) | |||
3254 | * MSI message composition | 3254 | * MSI message composition |
3255 | */ | 3255 | */ |
3256 | #ifdef CONFIG_PCI_MSI | 3256 | #ifdef CONFIG_PCI_MSI |
3257 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | 3257 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, |
3258 | struct msi_msg *msg, u8 hpet_id) | ||
3258 | { | 3259 | { |
3259 | struct irq_cfg *cfg; | 3260 | struct irq_cfg *cfg; |
3260 | int err; | 3261 | int err; |
@@ -3288,7 +3289,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms | |||
3288 | irte.dest_id = IRTE_DEST(dest); | 3289 | irte.dest_id = IRTE_DEST(dest); |
3289 | 3290 | ||
3290 | /* Set source-id of interrupt request */ | 3291 | /* Set source-id of interrupt request */ |
3291 | set_msi_sid(&irte, pdev); | 3292 | if (pdev) |
3293 | set_msi_sid(&irte, pdev); | ||
3294 | else | ||
3295 | set_hpet_sid(&irte, hpet_id); | ||
3292 | 3296 | ||
3293 | modify_irte(irq, &irte); | 3297 | modify_irte(irq, &irte); |
3294 | 3298 | ||
@@ -3453,7 +3457,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq) | |||
3453 | int ret; | 3457 | int ret; |
3454 | struct msi_msg msg; | 3458 | struct msi_msg msg; |
3455 | 3459 | ||
3456 | ret = msi_compose_msg(dev, irq, &msg); | 3460 | ret = msi_compose_msg(dev, irq, &msg, -1); |
3457 | if (ret < 0) | 3461 | if (ret < 0) |
3458 | return ret; | 3462 | return ret; |
3459 | 3463 | ||
@@ -3586,7 +3590,7 @@ int arch_setup_dmar_msi(unsigned int irq) | |||
3586 | int ret; | 3590 | int ret; |
3587 | struct msi_msg msg; | 3591 | struct msi_msg msg; |
3588 | 3592 | ||
3589 | ret = msi_compose_msg(NULL, irq, &msg); | 3593 | ret = msi_compose_msg(NULL, irq, &msg, -1); |
3590 | if (ret < 0) | 3594 | if (ret < 0) |
3591 | return ret; | 3595 | return ret; |
3592 | dmar_msi_write(irq, &msg); | 3596 | dmar_msi_write(irq, &msg); |
@@ -3626,6 +3630,19 @@ static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask) | |||
3626 | 3630 | ||
3627 | #endif /* CONFIG_SMP */ | 3631 | #endif /* CONFIG_SMP */ |
3628 | 3632 | ||
3633 | static struct irq_chip ir_hpet_msi_type = { | ||
3634 | .name = "IR-HPET_MSI", | ||
3635 | .unmask = hpet_msi_unmask, | ||
3636 | .mask = hpet_msi_mask, | ||
3637 | #ifdef CONFIG_INTR_REMAP | ||
3638 | .ack = ir_ack_apic_edge, | ||
3639 | #ifdef CONFIG_SMP | ||
3640 | .set_affinity = ir_set_msi_irq_affinity, | ||
3641 | #endif | ||
3642 | #endif | ||
3643 | .retrigger = ioapic_retrigger_irq, | ||
3644 | }; | ||
3645 | |||
3629 | static struct irq_chip hpet_msi_type = { | 3646 | static struct irq_chip hpet_msi_type = { |
3630 | .name = "HPET_MSI", | 3647 | .name = "HPET_MSI", |
3631 | .unmask = hpet_msi_unmask, | 3648 | .unmask = hpet_msi_unmask, |
@@ -3637,20 +3654,36 @@ static struct irq_chip hpet_msi_type = { | |||
3637 | .retrigger = ioapic_retrigger_irq, | 3654 | .retrigger = ioapic_retrigger_irq, |
3638 | }; | 3655 | }; |
3639 | 3656 | ||
3640 | int arch_setup_hpet_msi(unsigned int irq) | 3657 | int arch_setup_hpet_msi(unsigned int irq, unsigned int id) |
3641 | { | 3658 | { |
3642 | int ret; | 3659 | int ret; |
3643 | struct msi_msg msg; | 3660 | struct msi_msg msg; |
3644 | struct irq_desc *desc = irq_to_desc(irq); | 3661 | struct irq_desc *desc = irq_to_desc(irq); |
3645 | 3662 | ||
3646 | ret = msi_compose_msg(NULL, irq, &msg); | 3663 | if (intr_remapping_enabled) { |
3664 | struct intel_iommu *iommu = map_hpet_to_ir(id); | ||
3665 | int index; | ||
3666 | |||
3667 | if (!iommu) | ||
3668 | return -1; | ||
3669 | |||
3670 | index = alloc_irte(iommu, irq, 1); | ||
3671 | if (index < 0) | ||
3672 | return -1; | ||
3673 | } | ||
3674 | |||
3675 | ret = msi_compose_msg(NULL, irq, &msg, id); | ||
3647 | if (ret < 0) | 3676 | if (ret < 0) |
3648 | return ret; | 3677 | return ret; |
3649 | 3678 | ||
3650 | hpet_msi_write(irq, &msg); | 3679 | hpet_msi_write(irq, &msg); |
3651 | desc->status |= IRQ_MOVE_PCNTXT; | 3680 | desc->status |= IRQ_MOVE_PCNTXT; |
3652 | set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq, | 3681 | if (irq_remapped(irq)) |
3653 | "edge"); | 3682 | set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type, |
3683 | handle_edge_irq, "edge"); | ||
3684 | else | ||
3685 | set_irq_chip_and_handler_name(irq, &hpet_msi_type, | ||
3686 | handle_edge_irq, "edge"); | ||
3654 | 3687 | ||
3655 | return 0; | 3688 | return 0; |
3656 | } | 3689 | } |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index ba575f0f2e34..7f024ff47d1d 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
@@ -33,6 +33,7 @@ | |||
33 | * HPET address is set in acpi/boot.c, when an ACPI entry exists | 33 | * HPET address is set in acpi/boot.c, when an ACPI entry exists |
34 | */ | 34 | */ |
35 | unsigned long hpet_address; | 35 | unsigned long hpet_address; |
36 | u8 hpet_blockid; /* OS timer block num */ | ||
36 | #ifdef CONFIG_PCI_MSI | 37 | #ifdef CONFIG_PCI_MSI |
37 | static unsigned long hpet_num_timers; | 38 | static unsigned long hpet_num_timers; |
38 | #endif | 39 | #endif |
@@ -467,7 +468,7 @@ static int hpet_msi_next_event(unsigned long delta, | |||
467 | 468 | ||
468 | static int hpet_setup_msi_irq(unsigned int irq) | 469 | static int hpet_setup_msi_irq(unsigned int irq) |
469 | { | 470 | { |
470 | if (arch_setup_hpet_msi(irq)) { | 471 | if (arch_setup_hpet_msi(irq, hpet_blockid)) { |
471 | destroy_irq(irq); | 472 | destroy_irq(irq); |
472 | return -EINVAL; | 473 | return -EINVAL; |
473 | } | 474 | } |