mirror of
https://github.com/adulau/aha.git
synced 2025-01-04 07:03:38 +00:00
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>
This commit is contained in:
parent
b40d575bf0
commit
58ac1e76ce
3 changed files with 139 additions and 0 deletions
|
@ -6,6 +6,8 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/hpet.h>
|
||||
|
@ -25,6 +27,15 @@
|
|||
unsigned long hpet_address;
|
||||
static void __iomem *hpet_virt_address;
|
||||
|
||||
struct hpet_dev {
|
||||
struct clock_event_device evt;
|
||||
unsigned int num;
|
||||
int cpu;
|
||||
unsigned int irq;
|
||||
unsigned int flags;
|
||||
char name[10];
|
||||
};
|
||||
|
||||
unsigned long hpet_readl(unsigned long a)
|
||||
{
|
||||
return readl(hpet_virt_address + a);
|
||||
|
@ -304,6 +315,49 @@ static int hpet_legacy_next_event(unsigned long delta,
|
|||
return hpet_next_event(delta, evt, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* HPET MSI Support
|
||||
*/
|
||||
|
||||
void hpet_msi_unmask(unsigned int irq)
|
||||
{
|
||||
struct hpet_dev *hdev = get_irq_data(irq);
|
||||
unsigned long cfg;
|
||||
|
||||
/* unmask it */
|
||||
cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
|
||||
cfg |= HPET_TN_FSB;
|
||||
hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
|
||||
}
|
||||
|
||||
void hpet_msi_mask(unsigned int irq)
|
||||
{
|
||||
unsigned long cfg;
|
||||
struct hpet_dev *hdev = get_irq_data(irq);
|
||||
|
||||
/* mask it */
|
||||
cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
|
||||
cfg &= ~HPET_TN_FSB;
|
||||
hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
|
||||
}
|
||||
|
||||
void hpet_msi_write(unsigned int irq, struct msi_msg *msg)
|
||||
{
|
||||
struct hpet_dev *hdev = get_irq_data(irq);
|
||||
|
||||
hpet_writel(msg->data, HPET_Tn_ROUTE(hdev->num));
|
||||
hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hdev->num) + 4);
|
||||
}
|
||||
|
||||
void hpet_msi_read(unsigned int irq, struct msi_msg *msg)
|
||||
{
|
||||
struct hpet_dev *hdev = get_irq_data(irq);
|
||||
|
||||
msg->data = hpet_readl(HPET_Tn_ROUTE(hdev->num));
|
||||
msg->address_lo = hpet_readl(HPET_Tn_ROUTE(hdev->num) + 4);
|
||||
msg->address_hi = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clock source related code
|
||||
*/
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#endif
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/dmar.h>
|
||||
#include <linux/hpet.h>
|
||||
|
||||
#include <asm/idle.h>
|
||||
#include <asm/io.h>
|
||||
|
@ -56,6 +57,7 @@
|
|||
#include <asm/hypertransport.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/irq_remapping.h>
|
||||
#include <asm/hpet.h>
|
||||
|
||||
#include <mach_ipi.h>
|
||||
#include <mach_apic.h>
|
||||
|
@ -3522,6 +3524,68 @@ int arch_setup_dmar_msi(unsigned int irq)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HPET_TIMER
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
|
||||
{
|
||||
struct irq_cfg *cfg;
|
||||
struct irq_desc *desc;
|
||||
struct msi_msg msg;
|
||||
unsigned int dest;
|
||||
cpumask_t tmp;
|
||||
|
||||
cpus_and(tmp, mask, cpu_online_map);
|
||||
if (cpus_empty(tmp))
|
||||
return;
|
||||
|
||||
if (assign_irq_vector(irq, mask))
|
||||
return;
|
||||
|
||||
cfg = irq_cfg(irq);
|
||||
cpus_and(tmp, cfg->domain, mask);
|
||||
dest = cpu_mask_to_apicid(tmp);
|
||||
|
||||
hpet_msi_read(irq, &msg);
|
||||
|
||||
msg.data &= ~MSI_DATA_VECTOR_MASK;
|
||||
msg.data |= MSI_DATA_VECTOR(cfg->vector);
|
||||
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
|
||||
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
|
||||
|
||||
hpet_msi_write(irq, &msg);
|
||||
desc = irq_to_desc(irq);
|
||||
desc->affinity = mask;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
struct irq_chip hpet_msi_type = {
|
||||
.name = "HPET_MSI",
|
||||
.unmask = hpet_msi_unmask,
|
||||
.mask = hpet_msi_mask,
|
||||
.ack = ack_apic_edge,
|
||||
#ifdef CONFIG_SMP
|
||||
.set_affinity = hpet_msi_set_affinity,
|
||||
#endif
|
||||
.retrigger = ioapic_retrigger_irq,
|
||||
};
|
||||
|
||||
int arch_setup_hpet_msi(unsigned int irq)
|
||||
{
|
||||
int ret;
|
||||
struct msi_msg msg;
|
||||
|
||||
ret = msi_compose_msg(NULL, irq, &msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hpet_msi_write(irq, &msg);
|
||||
set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq,
|
||||
"edge");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_PCI_MSI */
|
||||
/*
|
||||
* Hypertransport interrupt support
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef ASM_X86__HPET_H
|
||||
#define ASM_X86__HPET_H
|
||||
|
||||
#include <linux/msi.h>
|
||||
|
||||
#ifdef CONFIG_HPET_TIMER
|
||||
|
||||
#define HPET_MMAP_SIZE 1024
|
||||
|
@ -10,6 +12,11 @@
|
|||
#define HPET_CFG 0x010
|
||||
#define HPET_STATUS 0x020
|
||||
#define HPET_COUNTER 0x0f0
|
||||
|
||||
#define HPET_Tn_CFG(n) (0x100 + 0x20 * n)
|
||||
#define HPET_Tn_CMP(n) (0x108 + 0x20 * n)
|
||||
#define HPET_Tn_ROUTE(n) (0x110 + 0x20 * n)
|
||||
|
||||
#define HPET_T0_CFG 0x100
|
||||
#define HPET_T0_CMP 0x108
|
||||
#define HPET_T0_ROUTE 0x110
|
||||
|
@ -65,6 +72,20 @@ extern void hpet_disable(void);
|
|||
extern unsigned long hpet_readl(unsigned long a);
|
||||
extern void force_hpet_resume(void);
|
||||
|
||||
extern void hpet_msi_unmask(unsigned int irq);
|
||||
extern void hpet_msi_mask(unsigned int irq);
|
||||
extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
|
||||
extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
extern int arch_setup_hpet_msi(unsigned int irq);
|
||||
#else
|
||||
static inline int arch_setup_hpet_msi(unsigned int irq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HPET_EMULATE_RTC
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
|
Loading…
Reference in a new issue