Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58ac1e76 authored by venkatesh.pallipadi@intel.com's avatar venkatesh.pallipadi@intel.com Committed by Ingo Molnar
Browse files

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: default avatarVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: default avatarShaohua Li <shaohua.li@intel.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent b40d575b
Loading
Loading
Loading
Loading
+54 −0
Original line number Diff line number Diff line
@@ -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
 */
+64 −0
Original line number Diff line number Diff line
@@ -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
+21 −0
Original line number Diff line number Diff line
#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>