diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 22:26:55 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 22:26:55 -0500 |
| commit | 849e8dea099aafa56db9e74b580b0d858b956533 (patch) | |
| tree | f97331389507608561e96e96a04546b84a8860fc | |
| parent | e069efb6bbf8f739a2e084183709b5eb76abf90d (diff) | |
| parent | 18ed61da985c57eea3fe8038b13fa2837c9b3c3f (diff) | |
Merge branch 'timers-for-linus-hpet' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timers-for-linus-hpet' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
x86: hpet: Make WARN_ON understandable
x86: arch specific support for remapping HPET MSIs
intr-remap: generic support for remapping HPET MSIs
x86, hpet: Simplify the HPET code
x86, hpet: Disable per-cpu hpet timer if ARAT is supported
| -rw-r--r-- | arch/x86/include/asm/hpet.h | 7 | ||||
| -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 | 77 | ||||
| -rw-r--r-- | drivers/pci/intr_remapping.c | 89 | ||||
| -rw-r--r-- | drivers/pci/intr_remapping.h | 7 | ||||
| -rw-r--r-- | include/linux/dmar.h | 10 | ||||
| -rw-r--r-- | include/linux/hpet.h | 2 |
8 files changed, 199 insertions, 43 deletions
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h index 1c22cb05ad6a..5d89fd2a3690 100644 --- a/arch/x86/include/asm/hpet.h +++ b/arch/x86/include/asm/hpet.h | |||
| @@ -65,11 +65,12 @@ | |||
| 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); |
| 71 | extern void hpet_disable(void); | 72 | extern void hpet_disable(void); |
| 72 | extern unsigned long hpet_readl(unsigned long a); | 73 | extern unsigned int hpet_readl(unsigned int a); |
| 73 | extern void force_hpet_resume(void); | 74 | extern void force_hpet_resume(void); |
| 74 | 75 | ||
| 75 | extern void hpet_msi_unmask(unsigned int irq); | 76 | extern void hpet_msi_unmask(unsigned int irq); |
| @@ -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 67e929b89875..87eee07da21f 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 c0b4468683f9..d5d498fbee4b 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
| @@ -3267,7 +3267,8 @@ void destroy_irq(unsigned int irq) | |||
| 3267 | * MSI message composition | 3267 | * MSI message composition |
| 3268 | */ | 3268 | */ |
| 3269 | #ifdef CONFIG_PCI_MSI | 3269 | #ifdef CONFIG_PCI_MSI |
| 3270 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | 3270 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, |
| 3271 | struct msi_msg *msg, u8 hpet_id) | ||
| 3271 | { | 3272 | { |
| 3272 | struct irq_cfg *cfg; | 3273 | struct irq_cfg *cfg; |
| 3273 | int err; | 3274 | int err; |
| @@ -3301,7 +3302,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms | |||
| 3301 | irte.dest_id = IRTE_DEST(dest); | 3302 | irte.dest_id = IRTE_DEST(dest); |
| 3302 | 3303 | ||
| 3303 | /* Set source-id of interrupt request */ | 3304 | /* Set source-id of interrupt request */ |
| 3304 | set_msi_sid(&irte, pdev); | 3305 | if (pdev) |
| 3306 | set_msi_sid(&irte, pdev); | ||
| 3307 | else | ||
| 3308 | set_hpet_sid(&irte, hpet_id); | ||
| 3305 | 3309 | ||
| 3306 | modify_irte(irq, &irte); | 3310 | modify_irte(irq, &irte); |
| 3307 | 3311 | ||
| @@ -3466,7 +3470,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq) | |||
| 3466 | int ret; | 3470 | int ret; |
| 3467 | struct msi_msg msg; | 3471 | struct msi_msg msg; |
| 3468 | 3472 | ||
| 3469 | ret = msi_compose_msg(dev, irq, &msg); | 3473 | ret = msi_compose_msg(dev, irq, &msg, -1); |
| 3470 | if (ret < 0) | 3474 | if (ret < 0) |
| 3471 | return ret; | 3475 | return ret; |
| 3472 | 3476 | ||
| @@ -3599,7 +3603,7 @@ int arch_setup_dmar_msi(unsigned int irq) | |||
| 3599 | int ret; | 3603 | int ret; |
| 3600 | struct msi_msg msg; | 3604 | struct msi_msg msg; |
| 3601 | 3605 | ||
| 3602 | ret = msi_compose_msg(NULL, irq, &msg); | 3606 | ret = msi_compose_msg(NULL, irq, &msg, -1); |
| 3603 | if (ret < 0) | 3607 | if (ret < 0) |
| 3604 | return ret; | 3608 | return ret; |
| 3605 | dmar_msi_write(irq, &msg); | 3609 | dmar_msi_write(irq, &msg); |
| @@ -3639,6 +3643,19 @@ static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask) | |||
| 3639 | 3643 | ||
| 3640 | #endif /* CONFIG_SMP */ | 3644 | #endif /* CONFIG_SMP */ |
| 3641 | 3645 | ||
| 3646 | static struct irq_chip ir_hpet_msi_type = { | ||
| 3647 | .name = "IR-HPET_MSI", | ||
| 3648 | .unmask = hpet_msi_unmask, | ||
| 3649 | .mask = hpet_msi_mask, | ||
| 3650 | #ifdef CONFIG_INTR_REMAP | ||
| 3651 | .ack = ir_ack_apic_edge, | ||
| 3652 | #ifdef CONFIG_SMP | ||
| 3653 | .set_affinity = ir_set_msi_irq_affinity, | ||
| 3654 | #endif | ||
| 3655 | #endif | ||
| 3656 | .retrigger = ioapic_retrigger_irq, | ||
| 3657 | }; | ||
| 3658 | |||
| 3642 | static struct irq_chip hpet_msi_type = { | 3659 | static struct irq_chip hpet_msi_type = { |
| 3643 | .name = "HPET_MSI", | 3660 | .name = "HPET_MSI", |
| 3644 | .unmask = hpet_msi_unmask, | 3661 | .unmask = hpet_msi_unmask, |
| @@ -3650,20 +3667,36 @@ static struct irq_chip hpet_msi_type = { | |||
| 3650 | .retrigger = ioapic_retrigger_irq, | 3667 | .retrigger = ioapic_retrigger_irq, |
| 3651 | }; | 3668 | }; |
| 3652 | 3669 | ||
| 3653 | int arch_setup_hpet_msi(unsigned int irq) | 3670 | int arch_setup_hpet_msi(unsigned int irq, unsigned int id) |
| 3654 | { | 3671 | { |
| 3655 | int ret; | 3672 | int ret; |
| 3656 | struct msi_msg msg; | 3673 | struct msi_msg msg; |
| 3657 | struct irq_desc *desc = irq_to_desc(irq); | 3674 | struct irq_desc *desc = irq_to_desc(irq); |
| 3658 | 3675 | ||
| 3659 | ret = msi_compose_msg(NULL, irq, &msg); | 3676 | if (intr_remapping_enabled) { |
| 3677 | struct intel_iommu *iommu = map_hpet_to_ir(id); | ||
| 3678 | int index; | ||
| 3679 | |||
| 3680 | if (!iommu) | ||
| 3681 | return -1; | ||
| 3682 | |||
| 3683 | index = alloc_irte(iommu, irq, 1); | ||
| 3684 | if (index < 0) | ||
| 3685 | return -1; | ||
| 3686 | } | ||
| 3687 | |||
| 3688 | ret = msi_compose_msg(NULL, irq, &msg, id); | ||
| 3660 | if (ret < 0) | 3689 | if (ret < 0) |
| 3661 | return ret; | 3690 | return ret; |
| 3662 | 3691 | ||
| 3663 | hpet_msi_write(irq, &msg); | 3692 | hpet_msi_write(irq, &msg); |
| 3664 | desc->status |= IRQ_MOVE_PCNTXT; | 3693 | desc->status |= IRQ_MOVE_PCNTXT; |
| 3665 | set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq, | 3694 | if (irq_remapped(irq)) |
| 3666 | "edge"); | 3695 | set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type, |
| 3696 | handle_edge_irq, "edge"); | ||
| 3697 | else | ||
| 3698 | set_irq_chip_and_handler_name(irq, &hpet_msi_type, | ||
| 3699 | handle_edge_irq, "edge"); | ||
| 3667 | 3700 | ||
| 3668 | return 0; | 3701 | return 0; |
| 3669 | } | 3702 | } |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index dedc2bddf7a5..ba6e65884603 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 |
| @@ -47,12 +48,12 @@ struct hpet_dev { | |||
| 47 | char name[10]; | 48 | char name[10]; |
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | unsigned long hpet_readl(unsigned long a) | 51 | inline unsigned int hpet_readl(unsigned int a) |
| 51 | { | 52 | { |
| 52 | return readl(hpet_virt_address + a); | 53 | return readl(hpet_virt_address + a); |
| 53 | } | 54 | } |
| 54 | 55 | ||
| 55 | static inline void hpet_writel(unsigned long d, unsigned long a) | 56 | static inline void hpet_writel(unsigned int d, unsigned int a) |
| 56 | { | 57 | { |
| 57 | writel(d, hpet_virt_address + a); | 58 | writel(d, hpet_virt_address + a); |
| 58 | } | 59 | } |
| @@ -167,7 +168,7 @@ do { \ | |||
| 167 | 168 | ||
| 168 | static void hpet_reserve_msi_timers(struct hpet_data *hd); | 169 | static void hpet_reserve_msi_timers(struct hpet_data *hd); |
| 169 | 170 | ||
| 170 | static void hpet_reserve_platform_timers(unsigned long id) | 171 | static void hpet_reserve_platform_timers(unsigned int id) |
| 171 | { | 172 | { |
| 172 | struct hpet __iomem *hpet = hpet_virt_address; | 173 | struct hpet __iomem *hpet = hpet_virt_address; |
| 173 | struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; | 174 | struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; |
| @@ -205,7 +206,7 @@ static void hpet_reserve_platform_timers(unsigned long id) | |||
| 205 | 206 | ||
| 206 | } | 207 | } |
| 207 | #else | 208 | #else |
| 208 | static void hpet_reserve_platform_timers(unsigned long id) { } | 209 | static void hpet_reserve_platform_timers(unsigned int id) { } |
| 209 | #endif | 210 | #endif |
| 210 | 211 | ||
| 211 | /* | 212 | /* |
| @@ -246,7 +247,7 @@ static void hpet_reset_counter(void) | |||
| 246 | 247 | ||
| 247 | static void hpet_start_counter(void) | 248 | static void hpet_start_counter(void) |
| 248 | { | 249 | { |
| 249 | unsigned long cfg = hpet_readl(HPET_CFG); | 250 | unsigned int cfg = hpet_readl(HPET_CFG); |
| 250 | cfg |= HPET_CFG_ENABLE; | 251 | cfg |= HPET_CFG_ENABLE; |
| 251 | hpet_writel(cfg, HPET_CFG); | 252 | hpet_writel(cfg, HPET_CFG); |
| 252 | } | 253 | } |
| @@ -271,7 +272,7 @@ static void hpet_resume_counter(void) | |||
| 271 | 272 | ||
| 272 | static void hpet_enable_legacy_int(void) | 273 | static void hpet_enable_legacy_int(void) |
| 273 | { | 274 | { |
| 274 | unsigned long cfg = hpet_readl(HPET_CFG); | 275 | unsigned int cfg = hpet_readl(HPET_CFG); |
| 275 | 276 | ||
| 276 | cfg |= HPET_CFG_LEGACY; | 277 | cfg |= HPET_CFG_LEGACY; |
| 277 | hpet_writel(cfg, HPET_CFG); | 278 | hpet_writel(cfg, HPET_CFG); |
| @@ -314,7 +315,7 @@ static int hpet_setup_msi_irq(unsigned int irq); | |||
| 314 | static void hpet_set_mode(enum clock_event_mode mode, | 315 | static void hpet_set_mode(enum clock_event_mode mode, |
| 315 | struct clock_event_device *evt, int timer) | 316 | struct clock_event_device *evt, int timer) |
| 316 | { | 317 | { |
| 317 | unsigned long cfg, cmp, now; | 318 | unsigned int cfg, cmp, now; |
| 318 | uint64_t delta; | 319 | uint64_t delta; |
| 319 | 320 | ||
| 320 | switch (mode) { | 321 | switch (mode) { |
| @@ -323,7 +324,7 @@ static void hpet_set_mode(enum clock_event_mode mode, | |||
| 323 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult; | 324 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult; |
| 324 | delta >>= evt->shift; | 325 | delta >>= evt->shift; |
| 325 | now = hpet_readl(HPET_COUNTER); | 326 | now = hpet_readl(HPET_COUNTER); |
| 326 | cmp = now + (unsigned long) delta; | 327 | cmp = now + (unsigned int) delta; |
| 327 | cfg = hpet_readl(HPET_Tn_CFG(timer)); | 328 | cfg = hpet_readl(HPET_Tn_CFG(timer)); |
| 328 | /* Make sure we use edge triggered interrupts */ | 329 | /* Make sure we use edge triggered interrupts */ |
| 329 | cfg &= ~HPET_TN_LEVEL; | 330 | cfg &= ~HPET_TN_LEVEL; |
| @@ -339,7 +340,7 @@ static void hpet_set_mode(enum clock_event_mode mode, | |||
| 339 | * (See AMD-8111 HyperTransport I/O Hub Data Sheet, | 340 | * (See AMD-8111 HyperTransport I/O Hub Data Sheet, |
| 340 | * Publication # 24674) | 341 | * Publication # 24674) |
| 341 | */ | 342 | */ |
| 342 | hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer)); | 343 | hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer)); |
| 343 | hpet_start_counter(); | 344 | hpet_start_counter(); |
| 344 | hpet_print_config(); | 345 | hpet_print_config(); |
| 345 | break; | 346 | break; |
| @@ -383,13 +384,24 @@ static int hpet_next_event(unsigned long delta, | |||
| 383 | hpet_writel(cnt, HPET_Tn_CMP(timer)); | 384 | hpet_writel(cnt, HPET_Tn_CMP(timer)); |
| 384 | 385 | ||
| 385 | /* | 386 | /* |
| 386 | * We need to read back the CMP register to make sure that | 387 | * We need to read back the CMP register on certain HPET |
| 387 | * what we wrote hit the chip before we compare it to the | 388 | * implementations (ATI chipsets) which seem to delay the |
| 388 | * counter. | 389 | * transfer of the compare register into the internal compare |
| 390 | * logic. With small deltas this might actually be too late as | ||
| 391 | * the counter could already be higher than the compare value | ||
| 392 | * at that point and we would wait for the next hpet interrupt | ||
| 393 | * forever. We found out that reading the CMP register back | ||
| 394 | * forces the transfer so we can rely on the comparison with | ||
| 395 | * the counter register below. If the read back from the | ||
| 396 | * compare register does not match the value we programmed | ||
| 397 | * then we might have a real hardware problem. We can not do | ||
| 398 | * much about it here, but at least alert the user/admin with | ||
| 399 | * a prominent warning. | ||
| 389 | */ | 400 | */ |
| 390 | WARN_ON_ONCE((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt); | 401 | WARN_ONCE(hpet_readl(HPET_Tn_CMP(timer)) != cnt, |
| 402 | KERN_WARNING "hpet: compare register read back failed.\n"); | ||
| 391 | 403 | ||
| 392 | return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; | 404 | return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; |
| 393 | } | 405 | } |
| 394 | 406 | ||
| 395 | static void hpet_legacy_set_mode(enum clock_event_mode mode, | 407 | static void hpet_legacy_set_mode(enum clock_event_mode mode, |
| @@ -415,7 +427,7 @@ static struct hpet_dev *hpet_devs; | |||
| 415 | void hpet_msi_unmask(unsigned int irq) | 427 | void hpet_msi_unmask(unsigned int irq) |
| 416 | { | 428 | { |
| 417 | struct hpet_dev *hdev = get_irq_data(irq); | 429 | struct hpet_dev *hdev = get_irq_data(irq); |
| 418 | unsigned long cfg; | 430 | unsigned int cfg; |
| 419 | 431 | ||
| 420 | /* unmask it */ | 432 | /* unmask it */ |
| 421 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); | 433 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); |
| @@ -425,7 +437,7 @@ void hpet_msi_unmask(unsigned int irq) | |||
| 425 | 437 | ||
| 426 | void hpet_msi_mask(unsigned int irq) | 438 | void hpet_msi_mask(unsigned int irq) |
| 427 | { | 439 | { |
| 428 | unsigned long cfg; | 440 | unsigned int cfg; |
| 429 | struct hpet_dev *hdev = get_irq_data(irq); | 441 | struct hpet_dev *hdev = get_irq_data(irq); |
| 430 | 442 | ||
| 431 | /* mask it */ | 443 | /* mask it */ |
| @@ -467,7 +479,7 @@ static int hpet_msi_next_event(unsigned long delta, | |||
| 467 | 479 | ||
| 468 | static int hpet_setup_msi_irq(unsigned int irq) | 480 | static int hpet_setup_msi_irq(unsigned int irq) |
| 469 | { | 481 | { |
| 470 | if (arch_setup_hpet_msi(irq)) { | 482 | if (arch_setup_hpet_msi(irq, hpet_blockid)) { |
| 471 | destroy_irq(irq); | 483 | destroy_irq(irq); |
| 472 | return -EINVAL; | 484 | return -EINVAL; |
| 473 | } | 485 | } |
| @@ -584,6 +596,8 @@ static void hpet_msi_capability_lookup(unsigned int start_timer) | |||
| 584 | unsigned int num_timers_used = 0; | 596 | unsigned int num_timers_used = 0; |
| 585 | int i; | 597 | int i; |
| 586 | 598 | ||
| 599 | if (boot_cpu_has(X86_FEATURE_ARAT)) | ||
| 600 | return; | ||
| 587 | id = hpet_readl(HPET_ID); | 601 | id = hpet_readl(HPET_ID); |
| 588 | 602 | ||
| 589 | num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); | 603 | num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); |
| @@ -598,7 +612,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer) | |||
| 598 | 612 | ||
| 599 | for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) { | 613 | for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) { |
| 600 | struct hpet_dev *hdev = &hpet_devs[num_timers_used]; | 614 | struct hpet_dev *hdev = &hpet_devs[num_timers_used]; |
| 601 | unsigned long cfg = hpet_readl(HPET_Tn_CFG(i)); | 615 | unsigned int cfg = hpet_readl(HPET_Tn_CFG(i)); |
| 602 | 616 | ||
| 603 | /* Only consider HPET timer with MSI support */ | 617 | /* Only consider HPET timer with MSI support */ |
| 604 | if (!(cfg & HPET_TN_FSB_CAP)) | 618 | if (!(cfg & HPET_TN_FSB_CAP)) |
| @@ -813,7 +827,7 @@ static int hpet_clocksource_register(void) | |||
| 813 | */ | 827 | */ |
| 814 | int __init hpet_enable(void) | 828 | int __init hpet_enable(void) |
| 815 | { | 829 | { |
| 816 | unsigned long id; | 830 | unsigned int id; |
| 817 | int i; | 831 | int i; |
| 818 | 832 | ||
| 819 | if (!is_hpet_capable()) | 833 | if (!is_hpet_capable()) |
| @@ -872,10 +886,8 @@ int __init hpet_enable(void) | |||
| 872 | 886 | ||
| 873 | if (id & HPET_ID_LEGSUP) { | 887 | if (id & HPET_ID_LEGSUP) { |
| 874 | hpet_legacy_clockevent_register(); | 888 | hpet_legacy_clockevent_register(); |
| 875 | hpet_msi_capability_lookup(2); | ||
| 876 | return 1; | 889 | return 1; |
| 877 | } | 890 | } |
| 878 | hpet_msi_capability_lookup(0); | ||
| 879 | return 0; | 891 | return 0; |
| 880 | 892 | ||
| 881 | out_nohpet: | 893 | out_nohpet: |
| @@ -908,9 +920,17 @@ static __init int hpet_late_init(void) | |||
| 908 | if (!hpet_virt_address) | 920 | if (!hpet_virt_address) |
| 909 | return -ENODEV; | 921 | return -ENODEV; |
| 910 | 922 | ||
| 923 | if (hpet_readl(HPET_ID) & HPET_ID_LEGSUP) | ||
| 924 | hpet_msi_capability_lookup(2); | ||
| 925 | else | ||
| 926 | hpet_msi_capability_lookup(0); | ||
| 927 | |||
| 911 | hpet_reserve_platform_timers(hpet_readl(HPET_ID)); | 928 | hpet_reserve_platform_timers(hpet_readl(HPET_ID)); |
| 912 | hpet_print_config(); | 929 | hpet_print_config(); |
| 913 | 930 | ||
| 931 | if (boot_cpu_has(X86_FEATURE_ARAT)) | ||
| 932 | return 0; | ||
| 933 | |||
| 914 | for_each_online_cpu(cpu) { | 934 | for_each_online_cpu(cpu) { |
| 915 | hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu); | 935 | hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu); |
| 916 | } | 936 | } |
| @@ -925,7 +945,7 @@ fs_initcall(hpet_late_init); | |||
| 925 | void hpet_disable(void) | 945 | void hpet_disable(void) |
| 926 | { | 946 | { |
| 927 | if (is_hpet_capable()) { | 947 | if (is_hpet_capable()) { |
| 928 | unsigned long cfg = hpet_readl(HPET_CFG); | 948 | unsigned int cfg = hpet_readl(HPET_CFG); |
| 929 | 949 | ||
| 930 | if (hpet_legacy_int_enabled) { | 950 | if (hpet_legacy_int_enabled) { |
| 931 | cfg &= ~HPET_CFG_LEGACY; | 951 | cfg &= ~HPET_CFG_LEGACY; |
| @@ -965,8 +985,8 @@ static int hpet_prev_update_sec; | |||
| 965 | static struct rtc_time hpet_alarm_time; | 985 | static struct rtc_time hpet_alarm_time; |
| 966 | static unsigned long hpet_pie_count; | 986 | static unsigned long hpet_pie_count; |
| 967 | static u32 hpet_t1_cmp; | 987 | static u32 hpet_t1_cmp; |
| 968 | static unsigned long hpet_default_delta; | 988 | static u32 hpet_default_delta; |
| 969 | static unsigned long hpet_pie_delta; | 989 | static u32 hpet_pie_delta; |
| 970 | static unsigned long hpet_pie_limit; | 990 | static unsigned long hpet_pie_limit; |
| 971 | 991 | ||
| 972 | static rtc_irq_handler irq_handler; | 992 | static rtc_irq_handler irq_handler; |
| @@ -1017,7 +1037,8 @@ EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler); | |||
| 1017 | */ | 1037 | */ |
| 1018 | int hpet_rtc_timer_init(void) | 1038 | int hpet_rtc_timer_init(void) |
| 1019 | { | 1039 | { |
| 1020 | unsigned long cfg, cnt, delta, flags; | 1040 | unsigned int cfg, cnt, delta; |
| 1041 | unsigned long flags; | ||
| 1021 | 1042 | ||
| 1022 | if (!is_hpet_enabled()) | 1043 | if (!is_hpet_enabled()) |
| 1023 | return 0; | 1044 | return 0; |
| @@ -1027,7 +1048,7 @@ int hpet_rtc_timer_init(void) | |||
| 1027 | 1048 | ||
| 1028 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; | 1049 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; |
| 1029 | clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT; | 1050 | clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT; |
| 1030 | hpet_default_delta = (unsigned long) clc; | 1051 | hpet_default_delta = clc; |
| 1031 | } | 1052 | } |
| 1032 | 1053 | ||
| 1033 | if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) | 1054 | if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) |
| @@ -1113,7 +1134,7 @@ int hpet_set_periodic_freq(unsigned long freq) | |||
| 1113 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; | 1134 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; |
| 1114 | do_div(clc, freq); | 1135 | do_div(clc, freq); |
| 1115 | clc >>= hpet_clockevent.shift; | 1136 | clc >>= hpet_clockevent.shift; |
| 1116 | hpet_pie_delta = (unsigned long) clc; | 1137 | hpet_pie_delta = clc; |
| 1117 | } | 1138 | } |
| 1118 | return 1; | 1139 | return 1; |
| 1119 | } | 1140 | } |
| @@ -1127,7 +1148,7 @@ EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq); | |||
| 1127 | 1148 | ||
| 1128 | static void hpet_rtc_timer_reinit(void) | 1149 | static void hpet_rtc_timer_reinit(void) |
| 1129 | { | 1150 | { |
| 1130 | unsigned long cfg, delta; | 1151 | unsigned int cfg, delta; |
| 1131 | int lost_ints = -1; | 1152 | int lost_ints = -1; |
| 1132 | 1153 | ||
| 1133 | if (unlikely(!hpet_rtc_flags)) { | 1154 | if (unlikely(!hpet_rtc_flags)) { |
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 0ed78a764ded..3b3658669bee 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #include <linux/dmar.h> | 2 | #include <linux/dmar.h> |
| 3 | #include <linux/spinlock.h> | 3 | #include <linux/spinlock.h> |
| 4 | #include <linux/jiffies.h> | 4 | #include <linux/jiffies.h> |
| 5 | #include <linux/hpet.h> | ||
| 5 | #include <linux/pci.h> | 6 | #include <linux/pci.h> |
| 6 | #include <linux/irq.h> | 7 | #include <linux/irq.h> |
| 7 | #include <asm/io_apic.h> | 8 | #include <asm/io_apic.h> |
| @@ -14,7 +15,8 @@ | |||
| 14 | #include "pci.h" | 15 | #include "pci.h" |
| 15 | 16 | ||
| 16 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; | 17 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; |
| 17 | static int ir_ioapic_num; | 18 | static struct hpet_scope ir_hpet[MAX_HPET_TBS]; |
| 19 | static int ir_ioapic_num, ir_hpet_num; | ||
| 18 | int intr_remapping_enabled; | 20 | int intr_remapping_enabled; |
| 19 | 21 | ||
| 20 | static int disable_intremap; | 22 | static int disable_intremap; |
| @@ -343,6 +345,16 @@ int flush_irte(int irq) | |||
| 343 | return rc; | 345 | return rc; |
| 344 | } | 346 | } |
| 345 | 347 | ||
| 348 | struct intel_iommu *map_hpet_to_ir(u8 hpet_id) | ||
| 349 | { | ||
| 350 | int i; | ||
| 351 | |||
| 352 | for (i = 0; i < MAX_HPET_TBS; i++) | ||
| 353 | if (ir_hpet[i].id == hpet_id) | ||
| 354 | return ir_hpet[i].iommu; | ||
| 355 | return NULL; | ||
| 356 | } | ||
| 357 | |||
| 346 | struct intel_iommu *map_ioapic_to_ir(int apic) | 358 | struct intel_iommu *map_ioapic_to_ir(int apic) |
| 347 | { | 359 | { |
| 348 | int i; | 360 | int i; |
| @@ -470,6 +482,36 @@ int set_ioapic_sid(struct irte *irte, int apic) | |||
| 470 | return 0; | 482 | return 0; |
| 471 | } | 483 | } |
| 472 | 484 | ||
| 485 | int set_hpet_sid(struct irte *irte, u8 id) | ||
| 486 | { | ||
| 487 | int i; | ||
| 488 | u16 sid = 0; | ||
| 489 | |||
| 490 | if (!irte) | ||
| 491 | return -1; | ||
| 492 | |||
| 493 | for (i = 0; i < MAX_HPET_TBS; i++) { | ||
| 494 | if (ir_hpet[i].id == id) { | ||
| 495 | sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn; | ||
| 496 | break; | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | if (sid == 0) { | ||
| 501 | pr_warning("Failed to set source-id of HPET block (%d)\n", id); | ||
| 502 | return -1; | ||
| 503 | } | ||
| 504 | |||
| 505 | /* | ||
| 506 | * Should really use SQ_ALL_16. Some platforms are broken. | ||
| 507 | * While we figure out the right quirks for these broken platforms, use | ||
| 508 | * SQ_13_IGNORE_3 for now. | ||
| 509 | */ | ||
| 510 | set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid); | ||
| 511 | |||
| 512 | return 0; | ||
| 513 | } | ||
| 514 | |||
| 473 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) | 515 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
| 474 | { | 516 | { |
| 475 | struct pci_dev *bridge; | 517 | struct pci_dev *bridge; |
| @@ -711,6 +753,34 @@ error: | |||
| 711 | return -1; | 753 | return -1; |
| 712 | } | 754 | } |
| 713 | 755 | ||
| 756 | static void ir_parse_one_hpet_scope(struct acpi_dmar_device_scope *scope, | ||
| 757 | struct intel_iommu *iommu) | ||
| 758 | { | ||
| 759 | struct acpi_dmar_pci_path *path; | ||
| 760 | u8 bus; | ||
| 761 | int count; | ||
| 762 | |||
| 763 | bus = scope->bus; | ||
| 764 | path = (struct acpi_dmar_pci_path *)(scope + 1); | ||
| 765 | count = (scope->length - sizeof(struct acpi_dmar_device_scope)) | ||
| 766 | / sizeof(struct acpi_dmar_pci_path); | ||
| 767 | |||
| 768 | while (--count > 0) { | ||
| 769 | /* | ||
| 770 | * Access PCI directly due to the PCI | ||
| 771 | * subsystem isn't initialized yet. | ||
| 772 | */ | ||
| 773 | bus = read_pci_config_byte(bus, path->dev, path->fn, | ||
| 774 | PCI_SECONDARY_BUS); | ||
| 775 | path++; | ||
| 776 | } | ||
| 777 | ir_hpet[ir_hpet_num].bus = bus; | ||
| 778 | ir_hpet[ir_hpet_num].devfn = PCI_DEVFN(path->dev, path->fn); | ||
| 779 | ir_hpet[ir_hpet_num].iommu = iommu; | ||
| 780 | ir_hpet[ir_hpet_num].id = scope->enumeration_id; | ||
| 781 | ir_hpet_num++; | ||
| 782 | } | ||
| 783 | |||
| 714 | static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, | 784 | static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, |
| 715 | struct intel_iommu *iommu) | 785 | struct intel_iommu *iommu) |
| 716 | { | 786 | { |
| @@ -740,8 +810,8 @@ static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, | |||
| 740 | ir_ioapic_num++; | 810 | ir_ioapic_num++; |
| 741 | } | 811 | } |
| 742 | 812 | ||
| 743 | static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | 813 | static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header, |
| 744 | struct intel_iommu *iommu) | 814 | struct intel_iommu *iommu) |
| 745 | { | 815 | { |
| 746 | struct acpi_dmar_hardware_unit *drhd; | 816 | struct acpi_dmar_hardware_unit *drhd; |
| 747 | struct acpi_dmar_device_scope *scope; | 817 | struct acpi_dmar_device_scope *scope; |
| @@ -765,6 +835,17 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | |||
| 765 | drhd->address); | 835 | drhd->address); |
| 766 | 836 | ||
| 767 | ir_parse_one_ioapic_scope(scope, iommu); | 837 | ir_parse_one_ioapic_scope(scope, iommu); |
| 838 | } else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) { | ||
| 839 | if (ir_hpet_num == MAX_HPET_TBS) { | ||
| 840 | printk(KERN_WARNING "Exceeded Max HPET blocks\n"); | ||
| 841 | return -1; | ||
| 842 | } | ||
| 843 | |||
| 844 | printk(KERN_INFO "HPET id %d under DRHD base" | ||
| 845 | " 0x%Lx\n", scope->enumeration_id, | ||
| 846 | drhd->address); | ||
| 847 | |||
| 848 | ir_parse_one_hpet_scope(scope, iommu); | ||
| 768 | } | 849 | } |
| 769 | start += scope->length; | 850 | start += scope->length; |
| 770 | } | 851 | } |
| @@ -785,7 +866,7 @@ int __init parse_ioapics_under_ir(void) | |||
| 785 | struct intel_iommu *iommu = drhd->iommu; | 866 | struct intel_iommu *iommu = drhd->iommu; |
| 786 | 867 | ||
| 787 | if (ecap_ir_support(iommu->ecap)) { | 868 | if (ecap_ir_support(iommu->ecap)) { |
| 788 | if (ir_parse_ioapic_scope(drhd->hdr, iommu)) | 869 | if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu)) |
| 789 | return -1; | 870 | return -1; |
| 790 | 871 | ||
| 791 | ir_supported = 1; | 872 | ir_supported = 1; |
diff --git a/drivers/pci/intr_remapping.h b/drivers/pci/intr_remapping.h index 63a263c18415..5662fecfee60 100644 --- a/drivers/pci/intr_remapping.h +++ b/drivers/pci/intr_remapping.h | |||
| @@ -7,4 +7,11 @@ struct ioapic_scope { | |||
| 7 | unsigned int devfn; /* PCI devfn number */ | 7 | unsigned int devfn; /* PCI devfn number */ |
| 8 | }; | 8 | }; |
| 9 | 9 | ||
| 10 | struct hpet_scope { | ||
| 11 | struct intel_iommu *iommu; | ||
| 12 | u8 id; | ||
| 13 | unsigned int bus; | ||
| 14 | unsigned int devfn; | ||
| 15 | }; | ||
| 16 | |||
| 10 | #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) | 17 | #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) |
diff --git a/include/linux/dmar.h b/include/linux/dmar.h index 5de4c9e5856d..d7cecc90ed34 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h | |||
| @@ -126,7 +126,9 @@ extern int free_irte(int irq); | |||
| 126 | extern int irq_remapped(int irq); | 126 | extern int irq_remapped(int irq); |
| 127 | extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); | 127 | extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); |
| 128 | extern struct intel_iommu *map_ioapic_to_ir(int apic); | 128 | extern struct intel_iommu *map_ioapic_to_ir(int apic); |
| 129 | extern struct intel_iommu *map_hpet_to_ir(u8 id); | ||
| 129 | extern int set_ioapic_sid(struct irte *irte, int apic); | 130 | extern int set_ioapic_sid(struct irte *irte, int apic); |
| 131 | extern int set_hpet_sid(struct irte *irte, u8 id); | ||
| 130 | extern int set_msi_sid(struct irte *irte, struct pci_dev *dev); | 132 | extern int set_msi_sid(struct irte *irte, struct pci_dev *dev); |
| 131 | #else | 133 | #else |
| 132 | static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | 134 | static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) |
| @@ -158,10 +160,18 @@ static inline struct intel_iommu *map_ioapic_to_ir(int apic) | |||
| 158 | { | 160 | { |
| 159 | return NULL; | 161 | return NULL; |
| 160 | } | 162 | } |
| 163 | static inline struct intel_iommu *map_hpet_to_ir(unsigned int hpet_id) | ||
| 164 | { | ||
| 165 | return NULL; | ||
| 166 | } | ||
| 161 | static inline int set_ioapic_sid(struct irte *irte, int apic) | 167 | static inline int set_ioapic_sid(struct irte *irte, int apic) |
| 162 | { | 168 | { |
| 163 | return 0; | 169 | return 0; |
| 164 | } | 170 | } |
| 171 | static inline int set_hpet_sid(struct irte *irte, u8 id) | ||
| 172 | { | ||
| 173 | return -1; | ||
| 174 | } | ||
| 165 | static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) | 175 | static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
| 166 | { | 176 | { |
| 167 | return 0; | 177 | return 0; |
diff --git a/include/linux/hpet.h b/include/linux/hpet.h index 79f63a27bcef..219ca4f6bea6 100644 --- a/include/linux/hpet.h +++ b/include/linux/hpet.h | |||
| @@ -126,4 +126,6 @@ struct hpet_info { | |||
| 126 | #define HPET_DPI _IO('h', 0x05) /* disable periodic */ | 126 | #define HPET_DPI _IO('h', 0x05) /* disable periodic */ |
| 127 | #define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */ | 127 | #define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */ |
| 128 | 128 | ||
| 129 | #define MAX_HPET_TBS 8 /* maximum hpet timer blocks */ | ||
| 130 | |||
| 129 | #endif /* !__HPET__ */ | 131 | #endif /* !__HPET__ */ |
