linux/drivers/iommu/irq_remapping.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   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_restore_boot_irq_mode(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_apic_ops.restore = irq_remapping_restore_boot_irq_mode;
  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 if (IS_ENABLED(CONFIG_HYPERV_IOMMU) &&
 108                 hyperv_irq_remap_ops.prepare() == 0)
 109                remap_ops = &hyperv_irq_remap_ops;
 110        else
 111                return -ENOSYS;
 112
 113        return 0;
 114}
 115
 116int __init irq_remapping_enable(void)
 117{
 118        int ret;
 119
 120        if (!remap_ops->enable)
 121                return -ENODEV;
 122
 123        ret = remap_ops->enable();
 124
 125        if (irq_remapping_enabled)
 126                irq_remapping_modify_x86_ops();
 127
 128        return ret;
 129}
 130
 131void irq_remapping_disable(void)
 132{
 133        if (irq_remapping_enabled && remap_ops->disable)
 134                remap_ops->disable();
 135}
 136
 137int irq_remapping_reenable(int mode)
 138{
 139        if (irq_remapping_enabled && remap_ops->reenable)
 140                return remap_ops->reenable(mode);
 141
 142        return 0;
 143}
 144
 145int __init irq_remap_enable_fault_handling(void)
 146{
 147        if (!irq_remapping_enabled)
 148                return 0;
 149
 150        if (!remap_ops->enable_faulting)
 151                return -ENODEV;
 152
 153        return remap_ops->enable_faulting();
 154}
 155
 156void panic_if_irq_remap(const char *msg)
 157{
 158        if (irq_remapping_enabled)
 159                panic(msg);
 160}
 161