aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/hpet.c54
-rw-r--r--arch/x86/kernel/io_apic.c64
-rw-r--r--include/asm-x86/hpet.h21
3 files changed, 139 insertions, 0 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index f7cb5e9e261e..3f10d16a8348 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -6,6 +6,8 @@
6#include <linux/init.h> 6#include <linux/init.h>
7#include <linux/sysdev.h> 7#include <linux/sysdev.h>
8#include <linux/pm.h> 8#include <linux/pm.h>
9#include <linux/interrupt.h>
10#include <linux/cpu.h>
9 11
10#include <asm/fixmap.h> 12#include <asm/fixmap.h>
11#include <asm/hpet.h> 13#include <asm/hpet.h>
@@ -25,6 +27,15 @@
25unsigned long hpet_address; 27unsigned long hpet_address;
26static void __iomem *hpet_virt_address; 28static void __iomem *hpet_virt_address;
27 29
30struct hpet_dev {
31 struct clock_event_device evt;
32 unsigned int num;
33 int cpu;
34 unsigned int irq;
35 unsigned int flags;
36 char name[10];
37};
38
28unsigned long hpet_readl(unsigned long a) 39unsigned long hpet_readl(unsigned long a)
29{ 40{
30 return readl(hpet_virt_address + a); 41 return readl(hpet_virt_address + a);
@@ -305,6 +316,49 @@ static int hpet_legacy_next_event(unsigned long delta,
305} 316}
306 317
307/* 318/*
319 * HPET MSI Support
320 */
321
322void hpet_msi_unmask(unsigned int irq)
323{
324 struct hpet_dev *hdev = get_irq_data(irq);
325 unsigned long cfg;
326
327 /* unmask it */
328 cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
329 cfg |= HPET_TN_FSB;
330 hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
331}
332
333void hpet_msi_mask(unsigned int irq)
334{
335 unsigned long cfg;
336 struct hpet_dev *hdev = get_irq_data(irq);
337
338 /* mask it */
339 cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
340 cfg &= ~HPET_TN_FSB;
341 hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
342}
343
344void hpet_msi_write(unsigned int irq, struct msi_msg *msg)
345{
346 struct hpet_dev *hdev = get_irq_data(irq);
347
348 hpet_writel(msg->data, HPET_Tn_ROUTE(hdev->num));
349 hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hdev->num) + 4);
350}
351
352void hpet_msi_read(unsigned int irq, struct msi_msg *msg)
353{
354 struct hpet_dev *hdev = get_irq_data(irq);
355
356 msg->data = hpet_readl(HPET_Tn_ROUTE(hdev->num));
357 msg->address_lo = hpet_readl(HPET_Tn_ROUTE(hdev->num) + 4);
358 msg->address_hi = 0;
359}
360
361/*
308 * Clock source related code 362 * Clock source related code
309 */ 363 */
310static cycle_t read_hpet(void) 364static cycle_t read_hpet(void)
diff --git a/arch/x86/kernel/io_apic.c b/arch/x86/kernel/io_apic.c
index d22fecf828b8..77fa155becf6 100644
--- a/arch/x86/kernel/io_apic.c
+++ b/arch/x86/kernel/io_apic.c
@@ -41,6 +41,7 @@
41#endif 41#endif
42#include <linux/bootmem.h> 42#include <linux/bootmem.h>
43#include <linux/dmar.h> 43#include <linux/dmar.h>
44#include <linux/hpet.h>
44 45
45#include <asm/idle.h> 46#include <asm/idle.h>
46#include <asm/io.h> 47#include <asm/io.h>
@@ -56,6 +57,7 @@
56#include <asm/hypertransport.h> 57#include <asm/hypertransport.h>
57#include <asm/setup.h> 58#include <asm/setup.h>
58#include <asm/irq_remapping.h> 59#include <asm/irq_remapping.h>
60#include <asm/hpet.h>
59 61
60#include <mach_ipi.h> 62#include <mach_ipi.h>
61#include <mach_apic.h> 63#include <mach_apic.h>
@@ -3522,6 +3524,68 @@ int arch_setup_dmar_msi(unsigned int irq)
3522} 3524}
3523#endif 3525#endif
3524 3526
3527#ifdef CONFIG_HPET_TIMER
3528
3529#ifdef CONFIG_SMP
3530static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
3531{
3532 struct irq_cfg *cfg;
3533 struct irq_desc *desc;
3534 struct msi_msg msg;
3535 unsigned int dest;
3536 cpumask_t tmp;
3537
3538 cpus_and(tmp, mask, cpu_online_map);
3539 if (cpus_empty(tmp))
3540 return;
3541
3542 if (assign_irq_vector(irq, mask))
3543 return;
3544
3545 cfg = irq_cfg(irq);
3546 cpus_and(tmp, cfg->domain, mask);
3547 dest = cpu_mask_to_apicid(tmp);
3548
3549 hpet_msi_read(irq, &msg);
3550
3551 msg.data &= ~MSI_DATA_VECTOR_MASK;
3552 msg.data |= MSI_DATA_VECTOR(cfg->vector);
3553 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
3554 msg.address_lo |= MSI_ADDR_DEST_ID(dest);
3555
3556 hpet_msi_write(irq, &msg);
3557 desc = irq_to_desc(irq);
3558 desc->affinity = mask;
3559}
3560#endif /* CONFIG_SMP */
3561
3562struct irq_chip hpet_msi_type = {
3563 .name = "HPET_MSI",
3564 .unmask = hpet_msi_unmask,
3565 .mask = hpet_msi_mask,
3566 .ack = ack_apic_edge,
3567#ifdef CONFIG_SMP
3568 .set_affinity = hpet_msi_set_affinity,
3569#endif
3570 .retrigger = ioapic_retrigger_irq,
3571};
3572
3573int arch_setup_hpet_msi(unsigned int irq)
3574{
3575 int ret;
3576 struct msi_msg msg;
3577
3578 ret = msi_compose_msg(NULL, irq, &msg);
3579 if (ret < 0)
3580 return ret;
3581
3582 hpet_msi_write(irq, &msg);
3583 set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq,
3584 "edge");
3585 return 0;
3586}
3587#endif
3588
3525#endif /* CONFIG_PCI_MSI */ 3589#endif /* CONFIG_PCI_MSI */
3526/* 3590/*
3527 * Hypertransport interrupt support 3591 * Hypertransport interrupt support
diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h
index cbbbb6d4dd32..58b273f6ef07 100644
--- a/include/asm-x86/hpet.h
+++ b/include/asm-x86/hpet.h
@@ -1,6 +1,8 @@
1#ifndef ASM_X86__HPET_H 1#ifndef ASM_X86__HPET_H
2#define ASM_X86__HPET_H 2#define ASM_X86__HPET_H
3 3
4#include <linux/msi.h>
5
4#ifdef CONFIG_HPET_TIMER 6#ifdef CONFIG_HPET_TIMER
5 7
6#define HPET_MMAP_SIZE 1024 8#define HPET_MMAP_SIZE 1024
@@ -10,6 +12,11 @@
10#define HPET_CFG 0x010 12#define HPET_CFG 0x010
11#define HPET_STATUS 0x020 13#define HPET_STATUS 0x020
12#define HPET_COUNTER 0x0f0 14#define HPET_COUNTER 0x0f0
15
16#define HPET_Tn_CFG(n) (0x100 + 0x20 * n)
17#define HPET_Tn_CMP(n) (0x108 + 0x20 * n)
18#define HPET_Tn_ROUTE(n) (0x110 + 0x20 * n)
19
13#define HPET_T0_CFG 0x100 20#define HPET_T0_CFG 0x100
14#define HPET_T0_CMP 0x108 21#define HPET_T0_CMP 0x108
15#define HPET_T0_ROUTE 0x110 22#define HPET_T0_ROUTE 0x110
@@ -65,6 +72,20 @@ extern void hpet_disable(void);
65extern unsigned long hpet_readl(unsigned long a); 72extern unsigned long hpet_readl(unsigned long a);
66extern void force_hpet_resume(void); 73extern void force_hpet_resume(void);
67 74
75extern void hpet_msi_unmask(unsigned int irq);
76extern void hpet_msi_mask(unsigned int irq);
77extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
78extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
79
80#ifdef CONFIG_PCI_MSI
81extern int arch_setup_hpet_msi(unsigned int irq);
82#else
83static inline int arch_setup_hpet_msi(unsigned int irq)
84{
85 return -EINVAL;
86}
87#endif
88
68#ifdef CONFIG_HPET_EMULATE_RTC 89#ifdef CONFIG_HPET_EMULATE_RTC
69 90
70#include <linux/interrupt.h> 91#include <linux/interrupt.h>