mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-06 06:35:12 +00:00
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: 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>
This commit is contained in:
parent
20f3097bfe
commit
c8bc6f3c80
4 changed files with 47 additions and 11 deletions
|
@ -65,6 +65,7 @@
|
||||||
/* hpet memory map physical address */
|
/* hpet memory map physical address */
|
||||||
extern unsigned long hpet_address;
|
extern unsigned long hpet_address;
|
||||||
extern unsigned long force_hpet_address;
|
extern unsigned long force_hpet_address;
|
||||||
|
extern u8 hpet_blockid;
|
||||||
extern int hpet_force_user;
|
extern int hpet_force_user;
|
||||||
extern int is_hpet_enabled(void);
|
extern int is_hpet_enabled(void);
|
||||||
extern int hpet_enable(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);
|
extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_MSI
|
#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
|
#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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -624,6 +624,7 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table)
|
||||||
}
|
}
|
||||||
|
|
||||||
hpet_address = hpet_tbl->address.address;
|
hpet_address = hpet_tbl->address.address;
|
||||||
|
hpet_blockid = hpet_tbl->sequence;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some broken BIOSes advertise HPET at 0x0. We really do not
|
* Some broken BIOSes advertise HPET at 0x0. We really do not
|
||||||
|
|
|
@ -3254,7 +3254,8 @@ void destroy_irq(unsigned int irq)
|
||||||
* MSI message composition
|
* MSI message composition
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_PCI_MSI
|
#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;
|
struct irq_cfg *cfg;
|
||||||
int err;
|
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);
|
irte.dest_id = IRTE_DEST(dest);
|
||||||
|
|
||||||
/* Set source-id of interrupt request */
|
/* 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);
|
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;
|
int ret;
|
||||||
struct msi_msg msg;
|
struct msi_msg msg;
|
||||||
|
|
||||||
ret = msi_compose_msg(dev, irq, &msg);
|
ret = msi_compose_msg(dev, irq, &msg, -1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -3586,7 +3590,7 @@ int arch_setup_dmar_msi(unsigned int irq)
|
||||||
int ret;
|
int ret;
|
||||||
struct msi_msg msg;
|
struct msi_msg msg;
|
||||||
|
|
||||||
ret = msi_compose_msg(NULL, irq, &msg);
|
ret = msi_compose_msg(NULL, irq, &msg, -1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
dmar_msi_write(irq, &msg);
|
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 */
|
#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 = {
|
static struct irq_chip hpet_msi_type = {
|
||||||
.name = "HPET_MSI",
|
.name = "HPET_MSI",
|
||||||
.unmask = hpet_msi_unmask,
|
.unmask = hpet_msi_unmask,
|
||||||
|
@ -3637,20 +3654,36 @@ static struct irq_chip hpet_msi_type = {
|
||||||
.retrigger = ioapic_retrigger_irq,
|
.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;
|
int ret;
|
||||||
struct msi_msg msg;
|
struct msi_msg msg;
|
||||||
struct irq_desc *desc = irq_to_desc(irq);
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
hpet_msi_write(irq, &msg);
|
hpet_msi_write(irq, &msg);
|
||||||
desc->status |= IRQ_MOVE_PCNTXT;
|
desc->status |= IRQ_MOVE_PCNTXT;
|
||||||
set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq,
|
if (irq_remapped(irq))
|
||||||
"edge");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
* HPET address is set in acpi/boot.c, when an ACPI entry exists
|
* HPET address is set in acpi/boot.c, when an ACPI entry exists
|
||||||
*/
|
*/
|
||||||
unsigned long hpet_address;
|
unsigned long hpet_address;
|
||||||
|
u8 hpet_blockid; /* OS timer block num */
|
||||||
#ifdef CONFIG_PCI_MSI
|
#ifdef CONFIG_PCI_MSI
|
||||||
static unsigned long hpet_num_timers;
|
static unsigned long hpet_num_timers;
|
||||||
#endif
|
#endif
|
||||||
|
@ -467,7 +468,7 @@ static int hpet_msi_next_event(unsigned long delta,
|
||||||
|
|
||||||
static int hpet_setup_msi_irq(unsigned int irq)
|
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);
|
destroy_irq(irq);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue