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

Commit c8bc6f3c authored by Suresh Siddha's avatar Suresh Siddha Committed by Thomas Gleixner
Browse files

x86: arch specific support for remapping HPET MSIs



x86 arch support for remapping HPET MSI's by associating the HPET timer block
with the interrupt-remapping HW unit and setting up appropriate irq_chip

Signed-off-by: default avatarSuresh Siddha <suresh.b.siddha@intel.com>
Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Jay Fenlason <fenlason@redhat.com>
LKML-Reference: <20090804190729.630510000@intel.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 20f3097b
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@
/* hpet memory map physical address */
extern unsigned long hpet_address;
extern unsigned long force_hpet_address;
extern u8 hpet_blockid;
extern int hpet_force_user;
extern int is_hpet_enabled(void);
extern int hpet_enable(void);
@@ -78,9 +79,9 @@ 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);
extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
#else
static inline int arch_setup_hpet_msi(unsigned int irq)
static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
{
	return -EINVAL;
}
+1 −0
Original line number Diff line number Diff line
@@ -624,6 +624,7 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table)
	}

	hpet_address = hpet_tbl->address.address;
	hpet_blockid = hpet_tbl->sequence;

	/*
	 * Some broken BIOSes advertise HPET at 0x0. We really do not
+41 −8
Original line number Diff line number Diff line
@@ -3254,7 +3254,8 @@ void destroy_irq(unsigned int irq)
 * MSI message composition
 */
#ifdef CONFIG_PCI_MSI
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
			   struct msi_msg *msg, u8 hpet_id)
{
	struct irq_cfg *cfg;
	int err;
@@ -3288,7 +3289,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
		irte.dest_id = IRTE_DEST(dest);

		/* Set source-id of interrupt request */
		if (pdev)
			set_msi_sid(&irte, pdev);
		else
			set_hpet_sid(&irte, hpet_id);

		modify_irte(irq, &irte);

@@ -3453,7 +3457,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
	int ret;
	struct msi_msg msg;

	ret = msi_compose_msg(dev, irq, &msg);
	ret = msi_compose_msg(dev, irq, &msg, -1);
	if (ret < 0)
		return ret;

@@ -3586,7 +3590,7 @@ int arch_setup_dmar_msi(unsigned int irq)
	int ret;
	struct msi_msg msg;

	ret = msi_compose_msg(NULL, irq, &msg);
	ret = msi_compose_msg(NULL, irq, &msg, -1);
	if (ret < 0)
		return ret;
	dmar_msi_write(irq, &msg);
@@ -3626,6 +3630,19 @@ static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)

#endif /* CONFIG_SMP */

static struct irq_chip ir_hpet_msi_type = {
	.name = "IR-HPET_MSI",
	.unmask = hpet_msi_unmask,
	.mask = hpet_msi_mask,
#ifdef CONFIG_INTR_REMAP
	.ack = ir_ack_apic_edge,
#ifdef CONFIG_SMP
	.set_affinity = ir_set_msi_irq_affinity,
#endif
#endif
	.retrigger = ioapic_retrigger_irq,
};

static struct irq_chip hpet_msi_type = {
	.name = "HPET_MSI",
	.unmask = hpet_msi_unmask,
@@ -3637,20 +3654,36 @@ static struct irq_chip hpet_msi_type = {
	.retrigger = ioapic_retrigger_irq,
};

int arch_setup_hpet_msi(unsigned int irq)
int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
{
	int ret;
	struct msi_msg msg;
	struct irq_desc *desc = irq_to_desc(irq);

	ret = msi_compose_msg(NULL, irq, &msg);
	if (intr_remapping_enabled) {
		struct intel_iommu *iommu = map_hpet_to_ir(id);
		int index;

		if (!iommu)
			return -1;

		index = alloc_irte(iommu, irq, 1);
		if (index < 0)
			return -1;
	}

	ret = msi_compose_msg(NULL, irq, &msg, id);
	if (ret < 0)
		return ret;

	hpet_msi_write(irq, &msg);
	desc->status |= IRQ_MOVE_PCNTXT;
	set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq,
		"edge");
	if (irq_remapped(irq))
		set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type,
					      handle_edge_irq, "edge");
	else
		set_irq_chip_and_handler_name(irq, &hpet_msi_type,
					      handle_edge_irq, "edge");

	return 0;
}
+2 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
 * HPET address is set in acpi/boot.c, when an ACPI entry exists
 */
unsigned long				hpet_address;
u8					hpet_blockid; /* OS timer block num */
#ifdef CONFIG_PCI_MSI
static unsigned long			hpet_num_timers;
#endif
@@ -467,7 +468,7 @@ static int hpet_msi_next_event(unsigned long delta,

static int hpet_setup_msi_irq(unsigned int irq)
{
	if (arch_setup_hpet_msi(irq)) {
	if (arch_setup_hpet_msi(irq, hpet_blockid)) {
		destroy_irq(irq);
		return -EINVAL;
	}