aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorvenkatesh.pallipadi@intel.com <venkatesh.pallipadi@intel.com>2008-09-05 21:02:17 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-16 10:53:07 -0400
commit58ac1e76ce77d515bd5cb65dbc465a040da341c6 (patch)
treee1bd9e60aaaa5098ea368c04043adf2a79fca604 /arch
parentb40d575bf0679c45aaf9e1161fc51a6b041b7210 (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>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/hpet.c54
-rw-r--r--arch/x86/kernel/io_apic.c64
2 files changed, 118 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