diff options
author | venkatesh.pallipadi@intel.com <venkatesh.pallipadi@intel.com> | 2008-09-05 21:02:17 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:53:07 -0400 |
commit | 58ac1e76ce77d515bd5cb65dbc465a040da341c6 (patch) | |
tree | e1bd9e60aaaa5098ea368c04043adf2a79fca604 | |
parent | b40d575bf0679c45aaf9e1161fc51a6b041b7210 (diff) |
x86: HPET_MSI Basic HPET_MSI setup code
Basic HPET MSI setup code. Routines to perform basic MSI read write
in HPET memory map and setting up irq_chip for HPET MSI.
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/hpet.c | 54 | ||||
-rw-r--r-- | arch/x86/kernel/io_apic.c | 64 | ||||
-rw-r--r-- | include/asm-x86/hpet.h | 21 |
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 @@ | |||
25 | unsigned long hpet_address; | 27 | unsigned long hpet_address; |
26 | static void __iomem *hpet_virt_address; | 28 | static void __iomem *hpet_virt_address; |
27 | 29 | ||
30 | struct 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 | |||
28 | unsigned long hpet_readl(unsigned long a) | 39 | unsigned 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 | |||
322 | void 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 | |||
333 | void 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 | |||
344 | void 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 | |||
352 | void 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 | */ |
310 | static cycle_t read_hpet(void) | 364 | static 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 | ||
3530 | static 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 | |||
3562 | struct 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 | |||
3573 | int 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); | |||
65 | extern unsigned long hpet_readl(unsigned long a); | 72 | extern unsigned long hpet_readl(unsigned long a); |
66 | extern void force_hpet_resume(void); | 73 | extern void force_hpet_resume(void); |
67 | 74 | ||
75 | extern void hpet_msi_unmask(unsigned int irq); | ||
76 | extern void hpet_msi_mask(unsigned int irq); | ||
77 | 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 | |||
80 | #ifdef CONFIG_PCI_MSI | ||
81 | extern int arch_setup_hpet_msi(unsigned int irq); | ||
82 | #else | ||
83 | static 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> |