diff options
Diffstat (limited to 'arch/x86/kernel/io_apic_64.c')
-rw-r--r-- | arch/x86/kernel/io_apic_64.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c index b3c2d268d708..953328b55a30 100644 --- a/arch/x86/kernel/io_apic_64.c +++ b/arch/x86/kernel/io_apic_64.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/sysdev.h> | 31 | #include <linux/sysdev.h> |
32 | #include <linux/msi.h> | 32 | #include <linux/msi.h> |
33 | #include <linux/htirq.h> | 33 | #include <linux/htirq.h> |
34 | #include <linux/dmar.h> | ||
34 | #ifdef CONFIG_ACPI | 35 | #ifdef CONFIG_ACPI |
35 | #include <acpi/acpi_bus.h> | 36 | #include <acpi/acpi_bus.h> |
36 | #endif | 37 | #endif |
@@ -2031,8 +2032,64 @@ void arch_teardown_msi_irq(unsigned int irq) | |||
2031 | destroy_irq(irq); | 2032 | destroy_irq(irq); |
2032 | } | 2033 | } |
2033 | 2034 | ||
2034 | #endif /* CONFIG_PCI_MSI */ | 2035 | #ifdef CONFIG_DMAR |
2036 | #ifdef CONFIG_SMP | ||
2037 | static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask) | ||
2038 | { | ||
2039 | struct irq_cfg *cfg = irq_cfg + irq; | ||
2040 | struct msi_msg msg; | ||
2041 | unsigned int dest; | ||
2042 | cpumask_t tmp; | ||
2043 | |||
2044 | cpus_and(tmp, mask, cpu_online_map); | ||
2045 | if (cpus_empty(tmp)) | ||
2046 | return; | ||
2047 | |||
2048 | if (assign_irq_vector(irq, mask)) | ||
2049 | return; | ||
2050 | |||
2051 | cpus_and(tmp, cfg->domain, mask); | ||
2052 | dest = cpu_mask_to_apicid(tmp); | ||
2053 | |||
2054 | dmar_msi_read(irq, &msg); | ||
2055 | |||
2056 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
2057 | msg.data |= MSI_DATA_VECTOR(cfg->vector); | ||
2058 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
2059 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
2060 | |||
2061 | dmar_msi_write(irq, &msg); | ||
2062 | irq_desc[irq].affinity = mask; | ||
2063 | } | ||
2064 | #endif /* CONFIG_SMP */ | ||
2065 | |||
2066 | struct irq_chip dmar_msi_type = { | ||
2067 | .name = "DMAR_MSI", | ||
2068 | .unmask = dmar_msi_unmask, | ||
2069 | .mask = dmar_msi_mask, | ||
2070 | .ack = ack_apic_edge, | ||
2071 | #ifdef CONFIG_SMP | ||
2072 | .set_affinity = dmar_msi_set_affinity, | ||
2073 | #endif | ||
2074 | .retrigger = ioapic_retrigger_irq, | ||
2075 | }; | ||
2076 | |||
2077 | int arch_setup_dmar_msi(unsigned int irq) | ||
2078 | { | ||
2079 | int ret; | ||
2080 | struct msi_msg msg; | ||
2081 | |||
2082 | ret = msi_compose_msg(NULL, irq, &msg); | ||
2083 | if (ret < 0) | ||
2084 | return ret; | ||
2085 | dmar_msi_write(irq, &msg); | ||
2086 | set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq, | ||
2087 | "edge"); | ||
2088 | return 0; | ||
2089 | } | ||
2090 | #endif | ||
2035 | 2091 | ||
2092 | #endif /* CONFIG_PCI_MSI */ | ||
2036 | /* | 2093 | /* |
2037 | * Hypertransport interrupt support | 2094 | * Hypertransport interrupt support |
2038 | */ | 2095 | */ |