Skip to content

Commit

Permalink
x86: arch specific support for remapping HPET MSIs
Browse files Browse the repository at this point in the history
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: Suresh 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: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Suresh Siddha authored and Thomas Gleixner committed Aug 27, 2009
1 parent 20f3097 commit c8bc6f3
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 11 deletions.
5 changes: 3 additions & 2 deletions arch/x86/include/asm/hpet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions arch/x86/kernel/acpi/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 41 additions & 8 deletions arch/x86/kernel/apic/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
set_msi_sid(&irte, pdev);
if (pdev)
set_msi_sid(&irte, pdev);
else
set_hpet_sid(&irte, hpet_id);

modify_irte(irq, &irte);

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion arch/x86/kernel/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit c8bc6f3

Please sign in to comment.