2019-05-19 15:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-09-26 14:44:35 +04:00
# include <linux/cpumask.h>
2012-03-30 22:47:00 +04:00
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/errno.h>
2012-07-06 15:28:37 +04:00
# include <linux/msi.h>
2012-09-26 14:44:38 +04:00
# include <linux/irq.h>
# include <linux/pci.h>
2015-04-13 09:11:29 +03:00
# include <linux/irqdomain.h>
2012-07-06 15:28:37 +04:00
# include <asm/hw_irq.h>
# include <asm/irq_remapping.h>
2012-09-26 14:44:35 +04:00
# include <asm/processor.h>
# include <asm/x86_init.h>
# include <asm/apic.h>
2014-09-17 13:32:19 +04:00
# include <asm/hpet.h>
2012-03-30 22:47:00 +04:00
2012-03-30 22:47:08 +04:00
# include "irq_remapping.h"
2012-03-30 22:47:00 +04:00
2012-03-30 22:47:07 +04:00
int irq_remapping_enabled ;
2013-04-17 00:38:32 +04:00
int irq_remap_broken ;
2012-03-30 22:47:00 +04:00
int disable_sourceid_checking ;
int no_x2apic_optout ;
2015-09-18 17:29:56 +03:00
int disable_irq_post = 0 ;
2015-06-09 08:20:35 +03:00
2015-01-07 10:31:42 +03:00
static int disable_irq_remap ;
2012-03-30 22:47:00 +04:00
static struct irq_remap_ops * remap_ops ;
2018-02-14 08:46:55 +03:00
static void irq_remapping_restore_boot_irq_mode ( void )
2012-09-26 14:44:35 +04:00
{
/*
* With interrupt - remapping , for now we will use virtual wire A
* mode , as virtual wire B is little complex ( need to configure
* both IOAPIC RTE as well as interrupt - remapping table entry ) .
* As this gets called during crash dump , keep this simple for
* now .
*/
2016-04-04 23:25:00 +03:00
if ( boot_cpu_has ( X86_FEATURE_APIC ) | | apic_from_smp_config ( ) )
2012-09-26 14:44:35 +04:00
disconnect_bsp_APIC ( 0 ) ;
}
static void __init irq_remapping_modify_x86_ops ( void )
{
2018-02-14 08:46:55 +03:00
x86_apic_ops . restore = irq_remapping_restore_boot_irq_mode ;
2012-09-26 14:44:35 +04:00
}
2012-03-30 22:47:00 +04:00
static __init int setup_nointremap ( char * str )
{
2012-03-30 22:47:07 +04:00
disable_irq_remap = 1 ;
2012-03-30 22:47:00 +04:00
return 0 ;
}
early_param ( " nointremap " , setup_nointremap ) ;
2012-03-30 22:47:07 +04:00
static __init int setup_irqremap ( char * str )
2012-03-30 22:47:00 +04:00
{
if ( ! str )
return - EINVAL ;
while ( * str ) {
2015-09-18 17:29:56 +03:00
if ( ! strncmp ( str , " on " , 2 ) ) {
2012-03-30 22:47:07 +04:00
disable_irq_remap = 0 ;
2015-09-18 17:29:56 +03:00
disable_irq_post = 0 ;
} else if ( ! strncmp ( str , " off " , 3 ) ) {
2012-03-30 22:47:07 +04:00
disable_irq_remap = 1 ;
2015-09-18 17:29:56 +03:00
disable_irq_post = 1 ;
} else if ( ! strncmp ( str , " nosid " , 5 ) )
2012-03-30 22:47:00 +04:00
disable_sourceid_checking = 1 ;
else if ( ! strncmp ( str , " no_x2apic_optout " , 16 ) )
no_x2apic_optout = 1 ;
2015-09-18 17:29:56 +03:00
else if ( ! strncmp ( str , " nopost " , 6 ) )
disable_irq_post = 1 ;
2012-03-30 22:47:00 +04:00
str + = strcspn ( str , " , " ) ;
while ( * str = = ' , ' )
str + + ;
}
return 0 ;
}
2012-03-30 22:47:07 +04:00
early_param ( " intremap " , setup_irqremap ) ;
2012-03-30 22:47:00 +04:00
2013-04-17 00:38:32 +04:00
void set_irq_remapping_broken ( void )
{
irq_remap_broken = 1 ;
}
2015-06-09 08:20:36 +03:00
bool irq_remapping_cap ( enum irq_remap_cap cap )
{
if ( ! remap_ops | | disable_irq_post )
2015-08-13 12:13:17 +03:00
return false ;
2015-06-09 08:20:36 +03:00
return ( remap_ops - > capability & ( 1 < < cap ) ) ;
}
EXPORT_SYMBOL_GPL ( irq_remapping_cap ) ;
2015-01-07 10:31:40 +03:00
int __init irq_remapping_prepare ( void )
2012-03-30 22:47:00 +04:00
{
2012-03-30 22:47:07 +04:00
if ( disable_irq_remap )
2015-01-07 10:31:40 +03:00
return - ENOSYS ;
2012-03-30 22:47:00 +04:00
2015-01-07 10:31:41 +03:00
if ( intel_irq_remap_ops . prepare ( ) = = 0 )
remap_ops = & intel_irq_remap_ops ;
else if ( IS_ENABLED ( CONFIG_AMD_IOMMU ) & &
amd_iommu_irq_ops . prepare ( ) = = 0 )
2015-01-07 10:31:28 +03:00
remap_ops = & amd_iommu_irq_ops ;
2019-02-27 17:54:04 +03:00
else if ( IS_ENABLED ( CONFIG_HYPERV_IOMMU ) & &
hyperv_irq_remap_ops . prepare ( ) = = 0 )
remap_ops = & hyperv_irq_remap_ops ;
2015-01-07 10:31:41 +03:00
else
return - ENOSYS ;
return 0 ;
2012-03-30 22:47:00 +04:00
}
2012-03-30 22:47:07 +04:00
int __init irq_remapping_enable ( void )
2012-03-30 22:47:00 +04:00
{
2012-09-26 14:44:35 +04:00
int ret ;
2015-01-07 10:31:43 +03:00
if ( ! remap_ops - > enable )
2012-03-30 22:47:00 +04:00
return - ENODEV ;
2012-09-26 14:44:35 +04:00
ret = remap_ops - > enable ( ) ;
if ( irq_remapping_enabled )
irq_remapping_modify_x86_ops ( ) ;
return ret ;
2012-03-30 22:47:00 +04:00
}
2012-03-30 22:47:01 +04:00
2012-03-30 22:47:07 +04:00
void irq_remapping_disable ( void )
2012-03-30 22:47:01 +04:00
{
2015-01-07 10:31:43 +03:00
if ( irq_remapping_enabled & & remap_ops - > disable )
remap_ops - > disable ( ) ;
2012-03-30 22:47:01 +04:00
}
2012-03-30 22:47:07 +04:00
int irq_remapping_reenable ( int mode )
2012-03-30 22:47:01 +04:00
{
2015-01-07 10:31:43 +03:00
if ( irq_remapping_enabled & & remap_ops - > reenable )
return remap_ops - > reenable ( mode ) ;
2012-03-30 22:47:01 +04:00
2015-01-07 10:31:43 +03:00
return 0 ;
2012-03-30 22:47:01 +04:00
}
2012-03-30 22:47:07 +04:00
int __init irq_remap_enable_fault_handling ( void )
2012-03-30 22:47:01 +04:00
{
2012-09-26 14:44:33 +04:00
if ( ! irq_remapping_enabled )
return 0 ;
2015-01-07 10:31:43 +03:00
if ( ! remap_ops - > enable_faulting )
2012-03-30 22:47:01 +04:00
return - ENODEV ;
return remap_ops - > enable_faulting ( ) ;
}
2012-03-30 22:47:02 +04:00
2012-09-26 14:44:41 +04:00
void panic_if_irq_remap ( const char * msg )
{
if ( irq_remapping_enabled )
panic ( msg ) ;
}