Commit 849e8dea099aafa56db9e74b580b0d858b956533
Exists in
master
and in
7 other branches
Merge branch 'timers-for-linus-hpet' of git://git.kernel.org/pub/scm/linux/kerne…
…l/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
Showing 8 changed files Side-by-side Diff
arch/x86/include/asm/hpet.h
... | ... | @@ -65,11 +65,12 @@ |
65 | 65 | /* hpet memory map physical address */ |
66 | 66 | extern unsigned long hpet_address; |
67 | 67 | extern unsigned long force_hpet_address; |
68 | +extern u8 hpet_blockid; | |
68 | 69 | extern int hpet_force_user; |
69 | 70 | extern int is_hpet_enabled(void); |
70 | 71 | extern int hpet_enable(void); |
71 | 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 | 74 | extern void force_hpet_resume(void); |
74 | 75 | |
75 | 76 | extern void hpet_msi_unmask(unsigned int irq); |
76 | 77 | |
... | ... | @@ -78,9 +79,9 @@ |
78 | 79 | extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg); |
79 | 80 | |
80 | 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 | 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 | 86 | return -EINVAL; |
86 | 87 | } |
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/io_apic.c
... | ... | @@ -3267,7 +3267,8 @@ |
3267 | 3267 | * MSI message composition |
3268 | 3268 | */ |
3269 | 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 | 3273 | struct irq_cfg *cfg; |
3273 | 3274 | int err; |
... | ... | @@ -3301,7 +3302,10 @@ |
3301 | 3302 | irte.dest_id = IRTE_DEST(dest); |
3302 | 3303 | |
3303 | 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 | 3310 | modify_irte(irq, &irte); |
3307 | 3311 | |
... | ... | @@ -3466,7 +3470,7 @@ |
3466 | 3470 | int ret; |
3467 | 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 | 3474 | if (ret < 0) |
3471 | 3475 | return ret; |
3472 | 3476 | |
... | ... | @@ -3599,7 +3603,7 @@ |
3599 | 3603 | int ret; |
3600 | 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 | 3607 | if (ret < 0) |
3604 | 3608 | return ret; |
3605 | 3609 | dmar_msi_write(irq, &msg); |
... | ... | @@ -3639,6 +3643,19 @@ |
3639 | 3643 | |
3640 | 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 | 3659 | static struct irq_chip hpet_msi_type = { |
3643 | 3660 | .name = "HPET_MSI", |
3644 | 3661 | .unmask = hpet_msi_unmask, |
3645 | 3662 | |
3646 | 3663 | |
... | ... | @@ -3650,20 +3667,36 @@ |
3650 | 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 | 3672 | int ret; |
3656 | 3673 | struct msi_msg msg; |
3657 | 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 | 3689 | if (ret < 0) |
3661 | 3690 | return ret; |
3662 | 3691 | |
3663 | 3692 | hpet_msi_write(irq, &msg); |
3664 | 3693 | desc->status |= IRQ_MOVE_PCNTXT; |
3665 | - set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq, | |
3666 | - "edge"); | |
3694 | + if (irq_remapped(irq)) | |
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 | 3701 | return 0; |
3669 | 3702 | } |
arch/x86/kernel/hpet.c
... | ... | @@ -33,6 +33,7 @@ |
33 | 33 | * HPET address is set in acpi/boot.c, when an ACPI entry exists |
34 | 34 | */ |
35 | 35 | unsigned long hpet_address; |
36 | +u8 hpet_blockid; /* OS timer block num */ | |
36 | 37 | #ifdef CONFIG_PCI_MSI |
37 | 38 | static unsigned long hpet_num_timers; |
38 | 39 | #endif |
39 | 40 | |
... | ... | @@ -47,12 +48,12 @@ |
47 | 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 | 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 | 58 | writel(d, hpet_virt_address + a); |
58 | 59 | } |
... | ... | @@ -167,7 +168,7 @@ |
167 | 168 | |
168 | 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 | 173 | struct hpet __iomem *hpet = hpet_virt_address; |
173 | 174 | struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; |
... | ... | @@ -205,7 +206,7 @@ |
205 | 206 | |
206 | 207 | } |
207 | 208 | #else |
208 | -static void hpet_reserve_platform_timers(unsigned long id) { } | |
209 | +static void hpet_reserve_platform_timers(unsigned int id) { } | |
209 | 210 | #endif |
210 | 211 | |
211 | 212 | /* |
... | ... | @@ -246,7 +247,7 @@ |
246 | 247 | |
247 | 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 | 251 | cfg |= HPET_CFG_ENABLE; |
251 | 252 | hpet_writel(cfg, HPET_CFG); |
252 | 253 | } |
... | ... | @@ -271,7 +272,7 @@ |
271 | 272 | |
272 | 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 | 277 | cfg |= HPET_CFG_LEGACY; |
277 | 278 | hpet_writel(cfg, HPET_CFG); |
... | ... | @@ -314,7 +315,7 @@ |
314 | 315 | static void hpet_set_mode(enum clock_event_mode mode, |
315 | 316 | struct clock_event_device *evt, int timer) |
316 | 317 | { |
317 | - unsigned long cfg, cmp, now; | |
318 | + unsigned int cfg, cmp, now; | |
318 | 319 | uint64_t delta; |
319 | 320 | |
320 | 321 | switch (mode) { |
... | ... | @@ -323,7 +324,7 @@ |
323 | 324 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult; |
324 | 325 | delta >>= evt->shift; |
325 | 326 | now = hpet_readl(HPET_COUNTER); |
326 | - cmp = now + (unsigned long) delta; | |
327 | + cmp = now + (unsigned int) delta; | |
327 | 328 | cfg = hpet_readl(HPET_Tn_CFG(timer)); |
328 | 329 | /* Make sure we use edge triggered interrupts */ |
329 | 330 | cfg &= ~HPET_TN_LEVEL; |
... | ... | @@ -339,7 +340,7 @@ |
339 | 340 | * (See AMD-8111 HyperTransport I/O Hub Data Sheet, |
340 | 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 | 344 | hpet_start_counter(); |
344 | 345 | hpet_print_config(); |
345 | 346 | break; |
346 | 347 | |
347 | 348 | |
... | ... | @@ -383,13 +384,24 @@ |
383 | 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 | - * what we wrote hit the chip before we compare it to the | |
388 | - * counter. | |
387 | + * We need to read back the CMP register on certain HPET | |
388 | + * implementations (ATI chipsets) which seem to delay the | |
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 | 407 | static void hpet_legacy_set_mode(enum clock_event_mode mode, |
... | ... | @@ -415,7 +427,7 @@ |
415 | 427 | void hpet_msi_unmask(unsigned int irq) |
416 | 428 | { |
417 | 429 | struct hpet_dev *hdev = get_irq_data(irq); |
418 | - unsigned long cfg; | |
430 | + unsigned int cfg; | |
419 | 431 | |
420 | 432 | /* unmask it */ |
421 | 433 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); |
... | ... | @@ -425,7 +437,7 @@ |
425 | 437 | |
426 | 438 | void hpet_msi_mask(unsigned int irq) |
427 | 439 | { |
428 | - unsigned long cfg; | |
440 | + unsigned int cfg; | |
429 | 441 | struct hpet_dev *hdev = get_irq_data(irq); |
430 | 442 | |
431 | 443 | /* mask it */ |
... | ... | @@ -467,7 +479,7 @@ |
467 | 479 | |
468 | 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 | 483 | destroy_irq(irq); |
472 | 484 | return -EINVAL; |
473 | 485 | } |
... | ... | @@ -584,6 +596,8 @@ |
584 | 596 | unsigned int num_timers_used = 0; |
585 | 597 | int i; |
586 | 598 | |
599 | + if (boot_cpu_has(X86_FEATURE_ARAT)) | |
600 | + return; | |
587 | 601 | id = hpet_readl(HPET_ID); |
588 | 602 | |
589 | 603 | num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); |
... | ... | @@ -598,7 +612,7 @@ |
598 | 612 | |
599 | 613 | for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) { |
600 | 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 | 617 | /* Only consider HPET timer with MSI support */ |
604 | 618 | if (!(cfg & HPET_TN_FSB_CAP)) |
... | ... | @@ -813,7 +827,7 @@ |
813 | 827 | */ |
814 | 828 | int __init hpet_enable(void) |
815 | 829 | { |
816 | - unsigned long id; | |
830 | + unsigned int id; | |
817 | 831 | int i; |
818 | 832 | |
819 | 833 | if (!is_hpet_capable()) |
820 | 834 | |
... | ... | @@ -872,10 +886,8 @@ |
872 | 886 | |
873 | 887 | if (id & HPET_ID_LEGSUP) { |
874 | 888 | hpet_legacy_clockevent_register(); |
875 | - hpet_msi_capability_lookup(2); | |
876 | 889 | return 1; |
877 | 890 | } |
878 | - hpet_msi_capability_lookup(0); | |
879 | 891 | return 0; |
880 | 892 | |
881 | 893 | out_nohpet: |
882 | 894 | |
... | ... | @@ -908,9 +920,17 @@ |
908 | 920 | if (!hpet_virt_address) |
909 | 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 | 928 | hpet_reserve_platform_timers(hpet_readl(HPET_ID)); |
912 | 929 | hpet_print_config(); |
913 | 930 | |
931 | + if (boot_cpu_has(X86_FEATURE_ARAT)) | |
932 | + return 0; | |
933 | + | |
914 | 934 | for_each_online_cpu(cpu) { |
915 | 935 | hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu); |
916 | 936 | } |
... | ... | @@ -925,7 +945,7 @@ |
925 | 945 | void hpet_disable(void) |
926 | 946 | { |
927 | 947 | if (is_hpet_capable()) { |
928 | - unsigned long cfg = hpet_readl(HPET_CFG); | |
948 | + unsigned int cfg = hpet_readl(HPET_CFG); | |
929 | 949 | |
930 | 950 | if (hpet_legacy_int_enabled) { |
931 | 951 | cfg &= ~HPET_CFG_LEGACY; |
... | ... | @@ -965,8 +985,8 @@ |
965 | 985 | static struct rtc_time hpet_alarm_time; |
966 | 986 | static unsigned long hpet_pie_count; |
967 | 987 | static u32 hpet_t1_cmp; |
968 | -static unsigned long hpet_default_delta; | |
969 | -static unsigned long hpet_pie_delta; | |
988 | +static u32 hpet_default_delta; | |
989 | +static u32 hpet_pie_delta; | |
970 | 990 | static unsigned long hpet_pie_limit; |
971 | 991 | |
972 | 992 | static rtc_irq_handler irq_handler; |
... | ... | @@ -1017,7 +1037,8 @@ |
1017 | 1037 | */ |
1018 | 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 | 1043 | if (!is_hpet_enabled()) |
1023 | 1044 | return 0; |
... | ... | @@ -1027,7 +1048,7 @@ |
1027 | 1048 | |
1028 | 1049 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; |
1029 | 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 | 1054 | if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) |
... | ... | @@ -1113,7 +1134,7 @@ |
1113 | 1134 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; |
1114 | 1135 | do_div(clc, freq); |
1115 | 1136 | clc >>= hpet_clockevent.shift; |
1116 | - hpet_pie_delta = (unsigned long) clc; | |
1137 | + hpet_pie_delta = clc; | |
1117 | 1138 | } |
1118 | 1139 | return 1; |
1119 | 1140 | } |
... | ... | @@ -1127,7 +1148,7 @@ |
1127 | 1148 | |
1128 | 1149 | static void hpet_rtc_timer_reinit(void) |
1129 | 1150 | { |
1130 | - unsigned long cfg, delta; | |
1151 | + unsigned int cfg, delta; | |
1131 | 1152 | int lost_ints = -1; |
1132 | 1153 | |
1133 | 1154 | if (unlikely(!hpet_rtc_flags)) { |
drivers/pci/intr_remapping.c
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | #include <linux/dmar.h> |
3 | 3 | #include <linux/spinlock.h> |
4 | 4 | #include <linux/jiffies.h> |
5 | +#include <linux/hpet.h> | |
5 | 6 | #include <linux/pci.h> |
6 | 7 | #include <linux/irq.h> |
7 | 8 | #include <asm/io_apic.h> |
... | ... | @@ -14,7 +15,8 @@ |
14 | 15 | #include "pci.h" |
15 | 16 | |
16 | 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 | 20 | int intr_remapping_enabled; |
19 | 21 | |
20 | 22 | static int disable_intremap; |
... | ... | @@ -343,6 +345,16 @@ |
343 | 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 | 358 | struct intel_iommu *map_ioapic_to_ir(int apic) |
347 | 359 | { |
348 | 360 | int i; |
... | ... | @@ -470,6 +482,36 @@ |
470 | 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 | 515 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
474 | 516 | { |
475 | 517 | struct pci_dev *bridge; |
... | ... | @@ -711,6 +753,34 @@ |
711 | 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 | 784 | static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, |
715 | 785 | struct intel_iommu *iommu) |
716 | 786 | { |
... | ... | @@ -740,8 +810,8 @@ |
740 | 810 | ir_ioapic_num++; |
741 | 811 | } |
742 | 812 | |
743 | -static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, | |
744 | - struct intel_iommu *iommu) | |
813 | +static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header, | |
814 | + struct intel_iommu *iommu) | |
745 | 815 | { |
746 | 816 | struct acpi_dmar_hardware_unit *drhd; |
747 | 817 | struct acpi_dmar_device_scope *scope; |
... | ... | @@ -765,6 +835,17 @@ |
765 | 835 | drhd->address); |
766 | 836 | |
767 | 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 | 850 | start += scope->length; |
770 | 851 | } |
... | ... | @@ -785,7 +866,7 @@ |
785 | 866 | struct intel_iommu *iommu = drhd->iommu; |
786 | 867 | |
787 | 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 | 870 | return -1; |
790 | 871 | |
791 | 872 | ir_supported = 1; |
drivers/pci/intr_remapping.h
include/linux/dmar.h
... | ... | @@ -126,7 +126,9 @@ |
126 | 126 | extern int irq_remapped(int irq); |
127 | 127 | extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); |
128 | 128 | extern struct intel_iommu *map_ioapic_to_ir(int apic); |
129 | +extern struct intel_iommu *map_hpet_to_ir(u8 id); | |
129 | 130 | extern int set_ioapic_sid(struct irte *irte, int apic); |
131 | +extern int set_hpet_sid(struct irte *irte, u8 id); | |
130 | 132 | extern int set_msi_sid(struct irte *irte, struct pci_dev *dev); |
131 | 133 | #else |
132 | 134 | static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) |
133 | 135 | |
... | ... | @@ -158,9 +160,17 @@ |
158 | 160 | { |
159 | 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 | 167 | static inline int set_ioapic_sid(struct irte *irte, int apic) |
162 | 168 | { |
163 | 169 | return 0; |
170 | +} | |
171 | +static inline int set_hpet_sid(struct irte *irte, u8 id) | |
172 | +{ | |
173 | + return -1; | |
164 | 174 | } |
165 | 175 | static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
166 | 176 | { |
include/linux/hpet.h