linux/drivers/iommu/irq_remapping.c
<<
>>
Prefs
   1#include <linux/seq_file.h>
   2#include <linux/cpumask.h>
   3#include <linux/kernel.h>
   4#include <linux/string.h>
   5#include <linux/errno.h>
   6#include <linux/msi.h>
   7#include <linux/irq.h>
   8#include <linux/pci.h>
   9#include <linux/irqdomain.h>
  10
  11#include <asm/hw_irq.h>
  12#include <asm/irq_remapping.h>
  13#include <asm/processor.h>
  14#include <asm/x86_init.h>
  15#include <asm/apic.h>
  16#include <asm/hpet.h>
  17
  18#include "irq_remapping.h"
  19
  20int irq_remapping_enabled;
  21int irq_remap_broken;
  22int disable_sourceid_checking;
  23int no_x2apic_optout;
  24
  25int disable_irq_post = 0;
  26
  27static int disable_irq_remap;
  28static struct irq_remap_ops *remap_ops;
  29
  30static void irq_remapping_disable_io_apic(void)
  31{
  32        /*
  33         * With interrupt-remapping, for now we will use virtual wire A
  34         * mode, as virtual wire B is little complex (need to configure
  35         * both IOAPIC RTE as well as interrupt-remapping table entry).
  36         * As this gets called during crash dump, keep this simple for
  37         * now.
  38         */
  39        if (boot_cpu_has(X86_FEATURE_APIC) || apic_from_smp_config())
  40                disconnect_bsp_APIC(0);
  41}
  42
  43static void __init irq_remapping_modify_x86_ops(void)
  44{
  45        x86_io_apic_ops.disable         = irq_remapping_disable_io_apic;
  46}
  47
  48static __init int setup_nointremap(char *str)
  49{
  50        disable_irq_remap = 1;
  51        return 0;
  52}
  53early_param("nointremap", setup_nointremap);
  54
  55static __init int setup_irqremap(char *str)
  56{
  57        if (!str)
  58                return -EINVAL;
  59
  60        while (*str) {
  61                if (!strncmp(str, "on", 2)) {
  62                        disable_irq_remap = 0;
  63                        disable_irq_post = 0;
  64                } else if (!strncmp(str, "off", 3)) {
  65                        disable_irq_remap = 1;
  66                        disable_irq_post = 1;
  67                } else if (!strncmp(str, "nosid", 5))
  68                        disable_sourceid_checking = 1;
  69                else if (!strncmp(str, "no_x2apic_optout", 16))
  70                        no_x2apic_optout = 1;
  71                else if (!strncmp(str, "nopost", 6))
  72                        disable_irq_post = 1;
  73
  74                str += strcspn(str, ",");
  75                while (*str == ',')
  76                        str++;
  77        }
  78
  79        return 0;
  80}
  81early_param("intremap", setup_irqremap);
  82
  83void set_irq_remapping_broken(void)
  84{
  85        irq_remap_broken = 1;
  86}
  87
  88bool irq_remapping_cap(enum irq_remap_cap cap)
  89{
  90        if (!remap_ops || disable_irq_post)
  91                return false;
  92
  93        return (remap_ops->capability & (1 << cap));
  94}
  95EXPORT_SYMBOL_GPL(irq_remapping_cap);
  96
  97int __init irq_remapping_prepare(void)
  98{
  99        if (disable_irq_remap)
 100                return -ENOSYS;
 101
 102        if (intel_irq_remap_ops.prepare() == 0)
 103                remap_ops = &intel_irq_remap_ops;
 104        else if (IS_ENABLED(CONFIG_AMD_IOMMU) &&
 105                 amd_iommu_irq_ops.prepare() == 0)
 106                remap_ops = &amd_iommu_irq_ops;
 107        else
 108                return -ENOSYS;
 109
 110        return 0;
 111}
 112
 113int __init irq_remapping_enable(void)
 114{
 115        int ret;
 116
 117        if (!remap_ops->enable)
 118                return -ENODEV;
 119
 120        ret = remap_ops->enable();
 121
 122        if (irq_remapping_enabled)
 123                irq_remapping_modify_x86_ops();
 124
 125        return ret;
 126}
 127
 128void irq_remapping_disable(void)
 129{
 130        if (irq_remapping_enabled && remap_ops->disable)
 131                remap_ops->disable();
 132}
 133
 134int irq_remapping_reenable(int mode)
 135{
 136        if (irq_remapping_enabled && remap_ops->reenable)
 137                return remap_ops->reenable(mode);
 138
 139        return 0;
 140}
 141
 142int __init irq_remap_enable_fault_handling(void)
 143{
 144        if (!irq_remapping_enabled)
 145                return 0;
 146
 147        if (!remap_ops->enable_faulting)
 148                return -ENODEV;
 149
 150        return remap_ops->enable_faulting();
 151}
 152
 153void panic_if_irq_remap(const char *msg)
 154{
 155        if (irq_remapping_enabled)
 156                panic(msg);
 157}
 158
 159void ir_ack_apic_edge(struct irq_data *data)
 160{
 161        ack_APIC_irq();
 162}
 163
 164/**
 165 * irq_remapping_get_ir_irq_domain - Get the irqdomain associated with the IOMMU
 166 *                                   device serving request @info
 167 * @info: interrupt allocation information, used to identify the IOMMU device
 168 *
 169 * It's used to get parent irqdomain for HPET and IOAPIC irqdomains.
 170 * Returns pointer to IRQ domain, or NULL on failure.
 171 */
 172struct irq_domain *
 173irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info)
 174{
 175        if (!remap_ops || !remap_ops->get_ir_irq_domain)
 176                return NULL;
 177
 178        return remap_ops->get_ir_irq_domain(info);
 179}
 180
 181/**
 182 * irq_remapping_get_irq_domain - Get the irqdomain serving the request @info
 183 * @info: interrupt allocation information, used to identify the IOMMU device
 184 *
 185 * There will be one PCI MSI/MSIX irqdomain associated with each interrupt
 186 * remapping device, so this interface is used to retrieve the PCI MSI/MSIX
 187 * irqdomain serving request @info.
 188 * Returns pointer to IRQ domain, or NULL on failure.
 189 */
 190struct irq_domain *
 191irq_remapping_get_irq_domain(struct irq_alloc_info *info)
 192{
 193        if (!remap_ops || !remap_ops->get_irq_domain)
 194                return NULL;
 195
 196        return remap_ops->get_irq_domain(info);
 197}
 198