1
0
Fork 0

Yet another large set of x86 interrupt management updates:

- Simplification and distangling of the MSI related functionality
 
    - Let IO/APIC construct the RTE entries from an MSI message instead of
      having IO/APIC specific code in the interrupt remapping drivers
 
    - Make the retrieval of the parent interrupt domain (vector or remap
      unit) less hardcoded and use the relevant irqdomain callbacks for
      selection.
 
    - Allow the handling of more than 255 CPUs without a virtualized IOMMU
      when the hypervisor supports it. This has made been possible by the
      above modifications and also simplifies the existing workaround in the
      HyperV specific virtual IOMMU.
 
    - Cleanup of the historical timer_works() irq flags related
      inconsistencies.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAl/Xxd8THHRnbHhAbGlu
 dXRyb25peC5kZQAKCRCmGPVMDXSYoYpOD/9C5TppNlPMUyx2SflH6bxt37pJEpln
 +hYTKsk+jSThntr5mfj+GifGvgmHOVBTGnlDUnUnrpN7TQmLFBzwTOtnBLW53AO2
 16/u0+Xci4LNCtEkaymf0Rq4MfsfriXHPJr0A/CnZ0tpHSf5QKHAiitSiGujdMlb
 gbq43+zXd+jNkH7vkOLPX/7dZVI1hNASQEevJu2tRR4xYTuXFdBxvLgYkHtYKKrK
 R1sbs6nI6yIzye2u4m4xGu29SxgUft+zdUf+UehJKM3yFmf51d9qpkX+kLaTWuaL
 VPsMItbn0kdvxwXQWO6DYnIAAnVKCklyHQJTZCoNq9Fe91OoByak1CEVspSOa1av
 JmycNSch4IYWasR4vVCB1gbb+V9SejcKu5SV3CDrEDqwkOIpfiqpriUXSCJTLlFd
 QOEDOLuuk/79Qs//J/tb/nJ4IuKv8WPudDfIlMro8wUsAr67DjD4mnXprZ+svwWx
 Ct/0/Memk+BSa0cw6pvg24BUZGN6zrufkBu2HKT9GOXRUdNkdLkiPhT8mK4T/O0l
 f90QCLjPSOJ/K/pLEWdUHEPmgC5Q9RsXOmwVGqX+RbjfP7mYTJXlmWnBb+cFNch0
 xFIH3SxVGylxxT06NX3SkvinrHj10CoAlmneefBlLtx6dF+2P84DAMZSF0OFToVI
 c2KMg5zoesI4bg==
 =8Gfs
 -----END PGP SIGNATURE-----

Merge tag 'x86-apic-2020-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 apic updates from Thomas Gleixner:
 "Yet another large set of x86 interrupt management updates:

   - Simplification and distangling of the MSI related functionality

   - Let IO/APIC construct the RTE entries from an MSI message instead
     of having IO/APIC specific code in the interrupt remapping drivers

   - Make the retrieval of the parent interrupt domain (vector or remap
     unit) less hardcoded and use the relevant irqdomain callbacks for
     selection.

   - Allow the handling of more than 255 CPUs without a virtualized
     IOMMU when the hypervisor supports it. This has made been possible
     by the above modifications and also simplifies the existing
     workaround in the HyperV specific virtual IOMMU.

   - Cleanup of the historical timer_works() irq flags related
     inconsistencies"

* tag 'x86-apic-2020-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (42 commits)
  x86/ioapic: Cleanup the timer_works() irqflags mess
  iommu/hyper-v: Remove I/O-APIC ID check from hyperv_irq_remapping_select()
  iommu/amd: Fix IOMMU interrupt generation in X2APIC mode
  iommu/amd: Don't register interrupt remapping irqdomain when IR is disabled
  iommu/amd: Fix union of bitfields in intcapxt support
  x86/ioapic: Correct the PCI/ISA trigger type selection
  x86/ioapic: Use I/O-APIC ID for finding irqdomain, not index
  x86/hyperv: Enable 15-bit APIC ID if the hypervisor supports it
  x86/kvm: Enable 15-bit extension when KVM_FEATURE_MSI_EXT_DEST_ID detected
  iommu/hyper-v: Disable IRQ pseudo-remapping if 15 bit APIC IDs are available
  x86/apic: Support 15 bits of APIC ID in MSI where available
  x86/ioapic: Handle Extended Destination ID field in RTE
  iommu/vt-d: Simplify intel_irq_remapping_select()
  x86: Kill all traces of irq_remapping_get_irq_domain()
  x86/ioapic: Use irq_find_matching_fwspec() to find remapping irqdomain
  x86/hpet: Use irq_find_matching_fwspec() to find remapping irqdomain
  iommu/hyper-v: Implement select() method on remapping irqdomain
  iommu/vt-d: Implement select() method on remapping irqdomain
  iommu/amd: Implement select() method on remapping irqdomain
  x86/apic: Add select() method on vector irqdomain
  ...
zero-sugar-mainline-defconfig
Linus Torvalds 2020-12-14 18:59:53 -08:00
commit 148842c98a
47 changed files with 1063 additions and 953 deletions

View File

@ -259,6 +259,7 @@ static inline u64 native_x2apic_icr_read(void)
extern int x2apic_mode;
extern int x2apic_phys;
extern void __init x2apic_set_max_apicid(u32 apicid);
extern void __init check_x2apic(void);
extern void x2apic_setup(void);
static inline int x2apic_enabled(void)
@ -305,11 +306,10 @@ struct apic {
void (*send_IPI_all)(int vector);
void (*send_IPI_self)(int vector);
/* dest_logical is used by the IPI functions */
u32 dest_logical;
u32 disable_esr;
u32 irq_delivery_mode;
u32 irq_dest_mode;
enum apic_delivery_modes delivery_mode;
bool dest_mode_logical;
u32 (*calc_dest_apicid)(unsigned int cpu);
@ -520,12 +520,10 @@ static inline void apic_smt_update(void) { }
#endif
struct msi_msg;
struct irq_cfg;
#ifdef CONFIG_PCI_MSI
void x86_vector_msi_compose_msg(struct irq_data *data, struct msi_msg *msg);
#else
# define x86_vector_msi_compose_msg NULL
#endif
extern void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg,
bool dmar);
extern void ioapic_zap_locks(void);

View File

@ -432,15 +432,13 @@ struct local_apic {
#define BAD_APICID 0xFFFFu
#endif
enum ioapic_irq_destination_types {
dest_Fixed = 0,
dest_LowestPrio = 1,
dest_SMI = 2,
dest__reserved_1 = 3,
dest_NMI = 4,
dest_INIT = 5,
dest__reserved_2 = 6,
dest_ExtINT = 7
enum apic_delivery_modes {
APIC_DELIVERY_MODE_FIXED = 0,
APIC_DELIVERY_MODE_LOWESTPRIO = 1,
APIC_DELIVERY_MODE_SMI = 2,
APIC_DELIVERY_MODE_NMI = 4,
APIC_DELIVERY_MODE_INIT = 5,
APIC_DELIVERY_MODE_EXTINT = 7,
};
#endif /* _ASM_X86_APICDEF_H */

View File

@ -74,17 +74,6 @@ extern void hpet_disable(void);
extern unsigned int hpet_readl(unsigned int a);
extern void force_hpet_resume(void);
struct irq_data;
struct hpet_channel;
struct irq_domain;
extern void hpet_msi_unmask(struct irq_data *data);
extern void hpet_msi_mask(struct irq_data *data);
extern void hpet_msi_write(struct hpet_channel *hc, struct msi_msg *msg);
extern struct irq_domain *hpet_create_irq_domain(int hpet_id);
extern int hpet_assign_irq(struct irq_domain *domain,
struct hpet_channel *hc, int dev_num);
#ifdef CONFIG_HPET_EMULATE_RTC
#include <linux/interrupt.h>

View File

@ -39,18 +39,16 @@ enum irq_alloc_type {
X86_IRQ_ALLOC_TYPE_PCI_MSI,
X86_IRQ_ALLOC_TYPE_PCI_MSIX,
X86_IRQ_ALLOC_TYPE_DMAR,
X86_IRQ_ALLOC_TYPE_AMDVI,
X86_IRQ_ALLOC_TYPE_UV,
X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT,
X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT,
};
struct ioapic_alloc_info {
int pin;
int node;
u32 trigger : 1;
u32 polarity : 1;
u32 valid : 1;
struct IO_APIC_route_entry *entry;
int pin;
int node;
u32 is_level : 1;
u32 active_low : 1;
u32 valid : 1;
};
struct uv_alloc_info {

View File

@ -23,6 +23,13 @@
#define HYPERV_CPUID_IMPLEMENT_LIMITS 0x40000005
#define HYPERV_CPUID_NESTED_FEATURES 0x4000000A
#define HYPERV_CPUID_VIRT_STACK_INTERFACE 0x40000081
#define HYPERV_VS_INTERFACE_EAX_SIGNATURE 0x31235356 /* "VS#1" */
#define HYPERV_CPUID_VIRT_STACK_PROPERTIES 0x40000082
/* Support for the extended IOAPIC RTE format */
#define HYPERV_VS_PROPERTIES_EAX_EXTENDED_IOAPIC_RTE BIT(2)
#define HYPERV_HYPERVISOR_PRESENT_BIT 0x80000000
#define HYPERV_CPUID_MIN 0x40000005
#define HYPERV_CPUID_MAX 0x4000ffff

View File

@ -13,15 +13,6 @@
* Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
*/
/* I/O Unit Redirection Table */
#define IO_APIC_REDIR_VECTOR_MASK 0x000FF
#define IO_APIC_REDIR_DEST_LOGICAL 0x00800
#define IO_APIC_REDIR_DEST_PHYSICAL 0x00000
#define IO_APIC_REDIR_SEND_PENDING (1 << 12)
#define IO_APIC_REDIR_REMOTE_IRR (1 << 14)
#define IO_APIC_REDIR_LEVEL_TRIGGER (1 << 15)
#define IO_APIC_REDIR_MASKED (1 << 16)
/*
* The structure of the IO-APIC:
*/
@ -65,52 +56,40 @@ union IO_APIC_reg_03 {
};
struct IO_APIC_route_entry {
__u32 vector : 8,
delivery_mode : 3, /* 000: FIXED
* 001: lowest prio
* 111: ExtINT
*/
dest_mode : 1, /* 0: physical, 1: logical */
delivery_status : 1,
polarity : 1,
irr : 1,
trigger : 1, /* 0: edge, 1: level */
mask : 1, /* 0: enabled, 1: disabled */
__reserved_2 : 15;
__u32 __reserved_3 : 24,
dest : 8;
} __attribute__ ((packed));
struct IR_IO_APIC_route_entry {
__u64 vector : 8,
zero : 3,
index2 : 1,
delivery_status : 1,
polarity : 1,
irr : 1,
trigger : 1,
mask : 1,
reserved : 31,
format : 1,
index : 15;
union {
struct {
u64 vector : 8,
delivery_mode : 3,
dest_mode_logical : 1,
delivery_status : 1,
active_low : 1,
irr : 1,
is_level : 1,
masked : 1,
reserved_0 : 15,
reserved_1 : 17,
virt_destid_8_14 : 7,
destid_0_7 : 8;
};
struct {
u64 ir_shared_0 : 8,
ir_zero : 3,
ir_index_15 : 1,
ir_shared_1 : 5,
ir_reserved_0 : 31,
ir_format : 1,
ir_index_0_14 : 15;
};
struct {
u64 w1 : 32,
w2 : 32;
};
};
} __attribute__ ((packed));
struct irq_alloc_info;
struct ioapic_domain_cfg;
#define IOAPIC_EDGE 0
#define IOAPIC_LEVEL 1
#define IOAPIC_MASKED 1
#define IOAPIC_UNMASKED 0
#define IOAPIC_POL_HIGH 0
#define IOAPIC_POL_LOW 1
#define IOAPIC_DEST_MODE_PHYSICAL 0
#define IOAPIC_DEST_MODE_LOGICAL 1
#define IOAPIC_MAP_ALLOC 0x1
#define IOAPIC_MAP_CHECK 0x2

View File

@ -44,9 +44,6 @@ extern int irq_remapping_reenable(int);
extern int irq_remap_enable_fault_handling(void);
extern void panic_if_irq_remap(const char *msg);
extern struct irq_domain *
irq_remapping_get_irq_domain(struct irq_alloc_info *info);
/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */
extern struct irq_domain *
arch_create_remap_msi_irq_domain(struct irq_domain *par, const char *n, int id);
@ -71,11 +68,5 @@ static inline void panic_if_irq_remap(const char *msg)
{
}
static inline struct irq_domain *
irq_remapping_get_irq_domain(struct irq_alloc_info *info)
{
return NULL;
}
#endif /* CONFIG_IRQ_REMAP */
#endif /* __X86_IRQ_REMAPPING_H */

View File

@ -12,6 +12,9 @@ enum {
X86_IRQ_ALLOC_LEGACY = 0x2,
};
extern int x86_fwspec_is_ioapic(struct irq_fwspec *fwspec);
extern int x86_fwspec_is_hpet(struct irq_fwspec *fwspec);
extern struct irq_domain *x86_vector_domain;
extern void init_irq_alloc_info(struct irq_alloc_info *info,

View File

@ -9,4 +9,54 @@ typedef struct irq_alloc_info msi_alloc_info_t;
int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
msi_alloc_info_t *arg);
/* Structs and defines for the X86 specific MSI message format */
typedef struct x86_msi_data {
u32 vector : 8,
delivery_mode : 3,
dest_mode_logical : 1,
reserved : 2,
active_low : 1,
is_level : 1;
u32 dmar_subhandle;
} __attribute__ ((packed)) arch_msi_msg_data_t;
#define arch_msi_msg_data x86_msi_data
typedef struct x86_msi_addr_lo {
union {
struct {
u32 reserved_0 : 2,
dest_mode_logical : 1,
redirect_hint : 1,
reserved_1 : 1,
virt_destid_8_14 : 7,
destid_0_7 : 8,
base_address : 12;
};
struct {
u32 dmar_reserved_0 : 2,
dmar_index_15 : 1,
dmar_subhandle_valid : 1,
dmar_format : 1,
dmar_index_0_14 : 15,
dmar_base_address : 12;
};
};
} __attribute__ ((packed)) arch_msi_msg_addr_lo_t;
#define arch_msi_msg_addr_lo x86_msi_addr_lo
#define X86_MSI_BASE_ADDRESS_LOW (0xfee00000 >> 20)
typedef struct x86_msi_addr_hi {
u32 reserved : 8,
destid_8_31 : 24;
} __attribute__ ((packed)) arch_msi_msg_addr_hi_t;
#define arch_msi_msg_addr_hi x86_msi_addr_hi
#define X86_MSI_BASE_ADDRESS_HIGH (0)
struct msi_msg;
u32 x86_msi_msg_get_destid(struct msi_msg *msg, bool extid);
#endif /* _ASM_X86_MSI_H */

View File

@ -1,57 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_X86_MSIDEF_H
#define _ASM_X86_MSIDEF_H
/*
* Constants for Intel APIC based MSI messages.
*/
/*
* Shifts for MSI data
*/
#define MSI_DATA_VECTOR_SHIFT 0
#define MSI_DATA_VECTOR_MASK 0x000000ff
#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & \
MSI_DATA_VECTOR_MASK)
#define MSI_DATA_DELIVERY_MODE_SHIFT 8
#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
#define MSI_DATA_LEVEL_SHIFT 14
#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
#define MSI_DATA_TRIGGER_SHIFT 15
#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
/*
* Shift/mask fields for msi address
*/
#define MSI_ADDR_BASE_HI 0
#define MSI_ADDR_BASE_LO 0xfee00000
#define MSI_ADDR_DEST_MODE_SHIFT 2
#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT)
#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT)
#define MSI_ADDR_REDIRECTION_SHIFT 3
#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
/* dedicated cpu */
#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
/* lowest priority */
#define MSI_ADDR_DEST_ID_SHIFT 12
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \
MSI_ADDR_DEST_ID_MASK)
#define MSI_ADDR_EXT_DEST_ID(dest) ((dest) & 0xffffff00)
#define MSI_ADDR_IR_EXT_INT (1 << 4)
#define MSI_ADDR_IR_SHV (1 << 3)
#define MSI_ADDR_IR_INDEX1(index) ((index & 0x8000) >> 13)
#define MSI_ADDR_IR_INDEX2(index) ((index & 0x7fff) << 5)
#endif /* _ASM_X86_MSIDEF_H */

View File

@ -116,6 +116,7 @@ struct x86_init_pci {
* @init_platform: platform setup
* @guest_late_init: guest late init
* @x2apic_available: X2APIC detection
* @msi_ext_dest_id: MSI supports 15-bit APIC IDs
* @init_mem_mapping: setup early mappings during init_mem_mapping()
* @init_after_bootmem: guest init after boot allocator is finished
*/
@ -123,6 +124,7 @@ struct x86_hyper_init {
void (*init_platform)(void);
void (*guest_late_init)(void);
bool (*x2apic_available)(void);
bool (*msi_ext_dest_id)(void);
void (*init_mem_mapping)(void);
void (*init_after_bootmem)(void);
};

View File

@ -93,6 +93,11 @@ static unsigned int disabled_cpu_apicid __ro_after_init = BAD_APICID;
*/
static int apic_extnmi __ro_after_init = APIC_EXTNMI_BSP;
/*
* Hypervisor supports 15 bits of APIC ID in MSI Extended Destination ID
*/
static bool virt_ext_dest_id __ro_after_init;
/*
* Map cpu index to physical APIC ID
*/
@ -1591,7 +1596,7 @@ static void setup_local_APIC(void)
apic->init_apic_ldr();
#ifdef CONFIG_X86_32
if (apic->dest_logical) {
if (apic->dest_mode_logical) {
int logical_apicid, ldr_apicid;
/*
@ -1841,20 +1846,34 @@ static __init void try_to_enable_x2apic(int remap_mode)
return;
if (remap_mode != IRQ_REMAP_X2APIC_MODE) {
/* IR is required if there is APIC ID > 255 even when running
* under KVM
u32 apic_limit = 255;
/*
* Using X2APIC without IR is not architecturally supported
* on bare metal but may be supported in guests.
*/
if (max_physical_apicid > 255 ||
!x86_init.hyper.x2apic_available()) {
if (!x86_init.hyper.x2apic_available()) {
pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n");
x2apic_disable();
return;
}
/*
* without IR all CPUs can be addressed by IOAPIC/MSI
* only in physical mode
* If the hypervisor supports extended destination ID in
* MSI, that increases the maximum APIC ID that can be
* used for non-remapped IRQ domains.
*/
if (x86_init.hyper.msi_ext_dest_id()) {
virt_ext_dest_id = 1;
apic_limit = 32767;
}
/*
* Without IR, all CPUs can be addressed by IOAPIC/MSI only
* in physical mode, and CPUs with an APIC ID that cannnot
* be addressed must not be brought online.
*/
x2apic_set_max_apicid(apic_limit);
x2apic_phys = 1;
}
x2apic_enable();
@ -2478,6 +2497,46 @@ int hard_smp_processor_id(void)
return read_apic_id();
}
void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg,
bool dmar)
{
memset(msg, 0, sizeof(*msg));
msg->arch_addr_lo.base_address = X86_MSI_BASE_ADDRESS_LOW;
msg->arch_addr_lo.dest_mode_logical = apic->dest_mode_logical;
msg->arch_addr_lo.destid_0_7 = cfg->dest_apicid & 0xFF;
msg->arch_data.delivery_mode = APIC_DELIVERY_MODE_FIXED;
msg->arch_data.vector = cfg->vector;
msg->address_hi = X86_MSI_BASE_ADDRESS_HIGH;
/*
* Only the IOMMU itself can use the trick of putting destination
* APIC ID into the high bits of the address. Anything else would
* just be writing to memory if it tried that, and needs IR to
* address APICs which can't be addressed in the normal 32-bit
* address range at 0xFFExxxxx. That is typically just 8 bits, but
* some hypervisors allow the extended destination ID field in bits
* 5-11 to be used, giving support for 15 bits of APIC IDs in total.
*/
if (dmar)
msg->arch_addr_hi.destid_8_31 = cfg->dest_apicid >> 8;
else if (virt_ext_dest_id && cfg->dest_apicid < 0x8000)
msg->arch_addr_lo.virt_destid_8_14 = cfg->dest_apicid >> 8;
else
WARN_ON_ONCE(cfg->dest_apicid > 0xFF);
}
u32 x86_msi_msg_get_destid(struct msi_msg *msg, bool extid)
{
u32 dest = msg->arch_addr_lo.destid_0_7;
if (extid)
dest |= msg->arch_addr_hi.destid_8_31 << 8;
return dest;
}
EXPORT_SYMBOL_GPL(x86_msi_msg_get_destid);
/*
* Override the generic EOI implementation with an optimized version.
* Only called during early boot when only one CPU is active and with

View File

@ -53,7 +53,7 @@ static void _flat_send_IPI_mask(unsigned long mask, int vector)
unsigned long flags;
local_irq_save(flags);
__default_send_IPI_dest_field(mask, vector, apic->dest_logical);
__default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
local_irq_restore(flags);
}
@ -113,15 +113,13 @@ static struct apic apic_flat __ro_after_init = {
.apic_id_valid = default_apic_id_valid,
.apic_id_registered = flat_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
.irq_dest_mode = 1, /* logical */
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = true,
.disable_esr = 0,
.dest_logical = APIC_DEST_LOGICAL,
.check_apicid_used = NULL,
.init_apic_ldr = flat_init_apic_ldr,
.ioapic_phys_id_map = NULL,
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,
@ -206,15 +204,13 @@ static struct apic apic_physflat __ro_after_init = {
.apic_id_valid = default_apic_id_valid,
.apic_id_registered = flat_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
.irq_dest_mode = 0, /* physical */
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = false,
.disable_esr = 0,
.dest_logical = 0,
.check_apicid_used = NULL,
.init_apic_ldr = physflat_init_apic_ldr,
.ioapic_phys_id_map = NULL,
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,

View File

@ -95,19 +95,15 @@ struct apic apic_noop __ro_after_init = {
.apic_id_valid = default_apic_id_valid,
.apic_id_registered = noop_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
/* logical delivery broadcast to all CPUs: */
.irq_dest_mode = 1,
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = true,
.disable_esr = 0,
.dest_logical = APIC_DEST_LOGICAL,
.check_apicid_used = default_check_apicid_used,
.init_apic_ldr = noop_init_apic_ldr,
.ioapic_phys_id_map = default_ioapic_phys_id_map,
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,
.apicid_to_cpu_present = physid_set_mask_of_physid,

View File

@ -246,15 +246,13 @@ static const struct apic apic_numachip1 __refconst = {
.apic_id_valid = numachip_apic_id_valid,
.apic_id_registered = numachip_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
.irq_dest_mode = 0, /* physical */
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = false,
.disable_esr = 0,
.dest_logical = 0,
.check_apicid_used = NULL,
.init_apic_ldr = flat_init_apic_ldr,
.ioapic_phys_id_map = NULL,
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,
@ -295,15 +293,13 @@ static const struct apic apic_numachip2 __refconst = {
.apic_id_valid = numachip_apic_id_valid,
.apic_id_registered = numachip_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
.irq_dest_mode = 0, /* physical */
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = false,
.disable_esr = 0,
.dest_logical = 0,
.check_apicid_used = NULL,
.init_apic_ldr = flat_init_apic_ldr,
.ioapic_phys_id_map = NULL,
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,

View File

@ -127,16 +127,13 @@ static struct apic apic_bigsmp __ro_after_init = {
.apic_id_valid = default_apic_id_valid,
.apic_id_registered = bigsmp_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
/* phys delivery to target CPU: */
.irq_dest_mode = 0,
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = false,
.disable_esr = 1,
.dest_logical = 0,
.check_apicid_used = bigsmp_check_apicid_used,
.init_apic_ldr = bigsmp_init_apic_ldr,
.ioapic_phys_id_map = bigsmp_ioapic_phys_id_map,
.setup_apic_routing = bigsmp_setup_apic_routing,
.cpu_present_to_apicid = bigsmp_cpu_present_to_apicid,

View File

@ -48,6 +48,7 @@
#include <linux/jiffies.h> /* time_after() */
#include <linux/slab.h>
#include <linux/memblock.h>
#include <linux/msi.h>
#include <asm/irqdomain.h>
#include <asm/io.h>
@ -63,7 +64,6 @@
#include <asm/setup.h>
#include <asm/irq_remapping.h>
#include <asm/hw_irq.h>
#include <asm/apic.h>
#define for_each_ioapic(idx) \
@ -89,12 +89,12 @@ struct irq_pin_list {
};
struct mp_chip_data {
struct list_head irq_2_pin;
struct IO_APIC_route_entry entry;
int trigger;
int polarity;
struct list_head irq_2_pin;
struct IO_APIC_route_entry entry;
bool is_level;
bool active_low;
bool isa_irq;
u32 count;
bool isa_irq;
};
struct mp_ioapic_gsi {
@ -286,31 +286,26 @@ static void io_apic_write(unsigned int apic, unsigned int reg,
writel(value, &io_apic->data);
}
union entry_union {
struct { u32 w1, w2; };
struct IO_APIC_route_entry entry;
};
static struct IO_APIC_route_entry __ioapic_read_entry(int apic, int pin)
{
union entry_union eu;
struct IO_APIC_route_entry entry;
eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
entry.w1 = io_apic_read(apic, 0x10 + 2 * pin);
entry.w2 = io_apic_read(apic, 0x11 + 2 * pin);
return eu.entry;
return entry;
}
static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
{
union entry_union eu;
struct IO_APIC_route_entry entry;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags);
eu.entry = __ioapic_read_entry(apic, pin);
entry = __ioapic_read_entry(apic, pin);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return eu.entry;
return entry;
}
/*
@ -321,11 +316,8 @@ static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
*/
static void __ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
{
union entry_union eu = {{0, 0}};
eu.entry = e;
io_apic_write(apic, 0x11 + 2*pin, eu.w2);
io_apic_write(apic, 0x10 + 2*pin, eu.w1);
io_apic_write(apic, 0x11 + 2*pin, e.w2);
io_apic_write(apic, 0x10 + 2*pin, e.w1);
}
static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
@ -344,12 +336,12 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
*/
static void ioapic_mask_entry(int apic, int pin)
{
struct IO_APIC_route_entry e = { .masked = true };
unsigned long flags;
union entry_union eu = { .entry.mask = IOAPIC_MASKED };
raw_spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(apic, 0x10 + 2*pin, eu.w1);
io_apic_write(apic, 0x11 + 2*pin, eu.w2);
io_apic_write(apic, 0x10 + 2*pin, e.w1);
io_apic_write(apic, 0x11 + 2*pin, e.w2);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
@ -422,20 +414,15 @@ static void __init replace_pin_at_irq_node(struct mp_chip_data *data, int node,
add_pin_to_irq_node(data, node, newapic, newpin);
}
static void io_apic_modify_irq(struct mp_chip_data *data,
int mask_and, int mask_or,
static void io_apic_modify_irq(struct mp_chip_data *data, bool masked,
void (*final)(struct irq_pin_list *entry))
{
union entry_union eu;
struct irq_pin_list *entry;
eu.entry = data->entry;
eu.w1 &= mask_and;
eu.w1 |= mask_or;
data->entry = eu.entry;
data->entry.masked = masked;
for_each_irq_pin(entry, data->irq_2_pin) {
io_apic_write(entry->apic, 0x10 + 2 * entry->pin, eu.w1);
io_apic_write(entry->apic, 0x10 + 2 * entry->pin, data->entry.w1);
if (final)
final(entry);
}
@ -459,13 +446,13 @@ static void mask_ioapic_irq(struct irq_data *irq_data)
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags);
io_apic_modify_irq(data, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
io_apic_modify_irq(data, true, &io_apic_sync);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
static void __unmask_ioapic(struct mp_chip_data *data)
{
io_apic_modify_irq(data, ~IO_APIC_REDIR_MASKED, 0, NULL);
io_apic_modify_irq(data, false, NULL);
}
static void unmask_ioapic_irq(struct irq_data *irq_data)
@ -506,8 +493,8 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector)
/*
* Mask the entry and change the trigger mode to edge.
*/
entry1.mask = IOAPIC_MASKED;
entry1.trigger = IOAPIC_EDGE;
entry1.masked = true;
entry1.is_level = false;
__ioapic_write_entry(apic, pin, entry1);
@ -535,15 +522,15 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
/* Check delivery_mode to be sure we're not clearing an SMI pin */
entry = ioapic_read_entry(apic, pin);
if (entry.delivery_mode == dest_SMI)
if (entry.delivery_mode == APIC_DELIVERY_MODE_SMI)
return;
/*
* Make sure the entry is masked and re-read the contents to check
* if it is a level triggered pin and if the remote-IRR is set.
*/
if (entry.mask == IOAPIC_UNMASKED) {
entry.mask = IOAPIC_MASKED;
if (!entry.masked) {
entry.masked = true;
ioapic_write_entry(apic, pin, entry);
entry = ioapic_read_entry(apic, pin);
}
@ -556,8 +543,8 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
* doesn't clear the remote-IRR if the trigger mode is not
* set to level.
*/
if (entry.trigger == IOAPIC_EDGE) {
entry.trigger = IOAPIC_LEVEL;
if (!entry.is_level) {
entry.is_level = true;
ioapic_write_entry(apic, pin, entry);
}
raw_spin_lock_irqsave(&ioapic_lock, flags);
@ -659,8 +646,8 @@ void mask_ioapic_entries(void)
struct IO_APIC_route_entry entry;
entry = ioapics[apic].saved_registers[pin];
if (entry.mask == IOAPIC_UNMASKED) {
entry.mask = IOAPIC_MASKED;
if (!entry.masked) {
entry.masked = true;
ioapic_write_entry(apic, pin, entry);
}
}
@ -745,44 +732,7 @@ static int __init find_isa_irq_apic(int irq, int type)
return -1;
}
#ifdef CONFIG_EISA
/*
* EISA Edge/Level control register, ELCR
*/
static int EISA_ELCR(unsigned int irq)
{
if (irq < nr_legacy_irqs()) {
unsigned int port = 0x4d0 + (irq >> 3);
return (inb(port) >> (irq & 7)) & 1;
}
apic_printk(APIC_VERBOSE, KERN_INFO
"Broken MPtable reports ISA irq %d\n", irq);
return 0;
}
#endif
/* ISA interrupts are always active high edge triggered,
* when listed as conforming in the MP table. */
#define default_ISA_trigger(idx) (IOAPIC_EDGE)
#define default_ISA_polarity(idx) (IOAPIC_POL_HIGH)
/* EISA interrupts are always polarity zero and can be edge or level
* trigger depending on the ELCR value. If an interrupt is listed as
* EISA conforming in the MP table, that means its trigger type must
* be read in from the ELCR */
#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].srcbusirq))
#define default_EISA_polarity(idx) default_ISA_polarity(idx)
/* PCI interrupts are always active low level triggered,
* when listed as conforming in the MP table. */
#define default_PCI_trigger(idx) (IOAPIC_LEVEL)
#define default_PCI_polarity(idx) (IOAPIC_POL_LOW)
static int irq_polarity(int idx)
static bool irq_active_low(int idx)
{
int bus = mp_irqs[idx].srcbus;
@ -791,90 +741,139 @@ static int irq_polarity(int idx)
*/
switch (mp_irqs[idx].irqflag & MP_IRQPOL_MASK) {
case MP_IRQPOL_DEFAULT:
/* conforms to spec, ie. bus-type dependent polarity */
if (test_bit(bus, mp_bus_not_pci))
return default_ISA_polarity(idx);
else
return default_PCI_polarity(idx);
/*
* Conforms to spec, ie. bus-type dependent polarity. PCI
* defaults to low active. [E]ISA defaults to high active.
*/
return !test_bit(bus, mp_bus_not_pci);
case MP_IRQPOL_ACTIVE_HIGH:
return IOAPIC_POL_HIGH;
return false;
case MP_IRQPOL_RESERVED:
pr_warn("IOAPIC: Invalid polarity: 2, defaulting to low\n");
fallthrough;
case MP_IRQPOL_ACTIVE_LOW:
default: /* Pointless default required due to do gcc stupidity */
return IOAPIC_POL_LOW;
return true;
}
}
#ifdef CONFIG_EISA
static int eisa_irq_trigger(int idx, int bus, int trigger)
/*
* EISA Edge/Level control register, ELCR
*/
static bool EISA_ELCR(unsigned int irq)
{
if (irq < nr_legacy_irqs()) {
unsigned int port = 0x4d0 + (irq >> 3);
return (inb(port) >> (irq & 7)) & 1;
}
apic_printk(APIC_VERBOSE, KERN_INFO
"Broken MPtable reports ISA irq %d\n", irq);
return false;
}
/*
* EISA interrupts are always active high and can be edge or level
* triggered depending on the ELCR value. If an interrupt is listed as
* EISA conforming in the MP table, that means its trigger type must be
* read in from the ELCR.
*/
static bool eisa_irq_is_level(int idx, int bus, bool level)
{
switch (mp_bus_id_to_type[bus]) {
case MP_BUS_PCI:
case MP_BUS_ISA:
return trigger;
return level;
case MP_BUS_EISA:
return default_EISA_trigger(idx);
return EISA_ELCR(mp_irqs[idx].srcbusirq);
}
pr_warn("IOAPIC: Invalid srcbus: %d defaulting to level\n", bus);
return IOAPIC_LEVEL;
return true;
}
#else
static inline int eisa_irq_trigger(int idx, int bus, int trigger)
static inline int eisa_irq_is_level(int idx, int bus, bool level)
{
return trigger;
return level;
}
#endif
static int irq_trigger(int idx)
static bool irq_is_level(int idx)
{
int bus = mp_irqs[idx].srcbus;
int trigger;
bool level;
/*
* Determine IRQ trigger mode (edge or level sensitive):
*/
switch (mp_irqs[idx].irqflag & MP_IRQTRIG_MASK) {
case MP_IRQTRIG_DEFAULT:
/* conforms to spec, ie. bus-type dependent trigger mode */
if (test_bit(bus, mp_bus_not_pci))
trigger = default_ISA_trigger(idx);
else
trigger = default_PCI_trigger(idx);
/*
* Conforms to spec, ie. bus-type dependent trigger
* mode. PCI defaults to level, ISA to edge.
*/
level = !test_bit(bus, mp_bus_not_pci);
/* Take EISA into account */
return eisa_irq_trigger(idx, bus, trigger);
return eisa_irq_is_level(idx, bus, level);
case MP_IRQTRIG_EDGE:
return IOAPIC_EDGE;
return false;
case MP_IRQTRIG_RESERVED:
pr_warn("IOAPIC: Invalid trigger mode 2 defaulting to level\n");
fallthrough;
case MP_IRQTRIG_LEVEL:
default: /* Pointless default required due to do gcc stupidity */
return IOAPIC_LEVEL;
return true;
}
}
static int __acpi_get_override_irq(u32 gsi, bool *trigger, bool *polarity)
{
int ioapic, pin, idx;
if (skip_ioapic_setup)
return -1;
ioapic = mp_find_ioapic(gsi);
if (ioapic < 0)
return -1;
pin = mp_find_ioapic_pin(ioapic, gsi);
if (pin < 0)
return -1;
idx = find_irq_entry(ioapic, pin, mp_INT);
if (idx < 0)
return -1;
*trigger = irq_is_level(idx);
*polarity = irq_active_low(idx);
return 0;
}
#ifdef CONFIG_ACPI
int acpi_get_override_irq(u32 gsi, int *is_level, int *active_low)
{
*is_level = *active_low = 0;
return __acpi_get_override_irq(gsi, (bool *)is_level,
(bool *)active_low);
}
#endif
void ioapic_set_alloc_attr(struct irq_alloc_info *info, int node,
int trigger, int polarity)
{
init_irq_alloc_info(info, NULL);
info->type = X86_IRQ_ALLOC_TYPE_IOAPIC;
info->ioapic.node = node;
info->ioapic.trigger = trigger;
info->ioapic.polarity = polarity;
info->ioapic.is_level = trigger;
info->ioapic.active_low = polarity;
info->ioapic.valid = 1;
}
#ifndef CONFIG_ACPI
int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
#endif
static void ioapic_copy_alloc_attr(struct irq_alloc_info *dst,
struct irq_alloc_info *src,
u32 gsi, int ioapic_idx, int pin)
{
int trigger, polarity;
bool level, pol_low;
copy_irq_alloc_info(dst, src);
dst->type = X86_IRQ_ALLOC_TYPE_IOAPIC;
@ -883,20 +882,20 @@ static void ioapic_copy_alloc_attr(struct irq_alloc_info *dst,
dst->ioapic.valid = 1;
if (src && src->ioapic.valid) {
dst->ioapic.node = src->ioapic.node;
dst->ioapic.trigger = src->ioapic.trigger;
dst->ioapic.polarity = src->ioapic.polarity;
dst->ioapic.is_level = src->ioapic.is_level;
dst->ioapic.active_low = src->ioapic.active_low;
} else {
dst->ioapic.node = NUMA_NO_NODE;
if (acpi_get_override_irq(gsi, &trigger, &polarity) >= 0) {
dst->ioapic.trigger = trigger;
dst->ioapic.polarity = polarity;
if (__acpi_get_override_irq(gsi, &level, &pol_low) >= 0) {
dst->ioapic.is_level = level;
dst->ioapic.active_low = pol_low;
} else {
/*
* PCI interrupts are always active low level
* triggered.
*/
dst->ioapic.trigger = IOAPIC_LEVEL;
dst->ioapic.polarity = IOAPIC_POL_LOW;
dst->ioapic.is_level = true;
dst->ioapic.active_low = true;
}
}
}
@ -906,12 +905,12 @@ static int ioapic_alloc_attr_node(struct irq_alloc_info *info)
return (info && info->ioapic.valid) ? info->ioapic.node : NUMA_NO_NODE;
}
static void mp_register_handler(unsigned int irq, unsigned long trigger)
static void mp_register_handler(unsigned int irq, bool level)
{
irq_flow_handler_t hdl;
bool fasteoi;
if (trigger) {
if (level) {
irq_set_status_flags(irq, IRQ_LEVEL);
fasteoi = true;
} else {
@ -933,14 +932,14 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info)
* pin with real trigger and polarity attributes.
*/
if (irq < nr_legacy_irqs() && data->count == 1) {
if (info->ioapic.trigger != data->trigger)
mp_register_handler(irq, info->ioapic.trigger);
data->entry.trigger = data->trigger = info->ioapic.trigger;
data->entry.polarity = data->polarity = info->ioapic.polarity;
if (info->ioapic.is_level != data->is_level)
mp_register_handler(irq, info->ioapic.is_level);
data->entry.is_level = data->is_level = info->ioapic.is_level;
data->entry.active_low = data->active_low = info->ioapic.active_low;
}
return data->trigger == info->ioapic.trigger &&
data->polarity == info->ioapic.polarity;
return data->is_level == info->ioapic.is_level &&
data->active_low == info->ioapic.active_low;
}
static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
@ -1219,10 +1218,9 @@ void ioapic_zap_locks(void)
static void io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
{
int i;
char buf[256];
struct IO_APIC_route_entry entry;
struct IR_IO_APIC_route_entry *ir_entry = (void *)&entry;
char buf[256];
int i;
printk(KERN_DEBUG "IOAPIC %d:\n", apic);
for (i = 0; i <= nr_entries; i++) {
@ -1230,20 +1228,21 @@ static void io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
snprintf(buf, sizeof(buf),
" pin%02x, %s, %s, %s, V(%02X), IRR(%1d), S(%1d)",
i,
entry.mask == IOAPIC_MASKED ? "disabled" : "enabled ",
entry.trigger == IOAPIC_LEVEL ? "level" : "edge ",
entry.polarity == IOAPIC_POL_LOW ? "low " : "high",
entry.masked ? "disabled" : "enabled ",
entry.is_level ? "level" : "edge ",
entry.active_low ? "low " : "high",
entry.vector, entry.irr, entry.delivery_status);
if (ir_entry->format)
if (entry.ir_format) {
printk(KERN_DEBUG "%s, remapped, I(%04X), Z(%X)\n",
buf, (ir_entry->index2 << 15) | ir_entry->index,
ir_entry->zero);
else
printk(KERN_DEBUG "%s, %s, D(%02X), M(%1d)\n",
buf,
entry.dest_mode == IOAPIC_DEST_MODE_LOGICAL ?
"logical " : "physical",
entry.dest, entry.delivery_mode);
(entry.ir_index_15 << 15) | entry.ir_index_0_14,
entry.ir_zero);
} else {
printk(KERN_DEBUG "%s, %s, D(%02X%02X), M(%1d)\n", buf,
entry.dest_mode_logical ? "logical " : "physical",
entry.virt_destid_8_14, entry.destid_0_7,
entry.delivery_mode);
}
}
}
@ -1368,7 +1367,8 @@ void __init enable_IO_APIC(void)
/* If the interrupt line is enabled and in ExtInt mode
* I have found the pin where the i8259 is connected.
*/
if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) {
if (!entry.masked &&
entry.delivery_mode == APIC_DELIVERY_MODE_EXTINT) {
ioapic_i8259.apic = apic;
ioapic_i8259.pin = pin;
goto found_i8259;
@ -1410,14 +1410,16 @@ void native_restore_boot_irq_mode(void)
*/
if (ioapic_i8259.pin != -1) {
struct IO_APIC_route_entry entry;
u32 apic_id = read_apic_id();
memset(&entry, 0, sizeof(entry));
entry.mask = IOAPIC_UNMASKED;
entry.trigger = IOAPIC_EDGE;
entry.polarity = IOAPIC_POL_HIGH;
entry.dest_mode = IOAPIC_DEST_MODE_PHYSICAL;
entry.delivery_mode = dest_ExtINT;
entry.dest = read_apic_id();
entry.masked = false;
entry.is_level = false;
entry.active_low = false;
entry.dest_mode_logical = false;
entry.delivery_mode = APIC_DELIVERY_MODE_EXTINT;
entry.destid_0_7 = apic_id & 0xFF;
entry.virt_destid_8_14 = apic_id >> 8;
/*
* Add it to the IO-APIC irq-routing table:
@ -1618,21 +1620,16 @@ static void __init delay_without_tsc(void)
static int __init timer_irq_works(void)
{
unsigned long t1 = jiffies;
unsigned long flags;
if (no_timer_check)
return 1;
local_save_flags(flags);
local_irq_enable();
if (boot_cpu_has(X86_FEATURE_TSC))
delay_with_tsc();
else
delay_without_tsc();
local_irq_restore(flags);
/*
* Expect a few ticks at least, to be sure some possible
* glue logic does not lock up after one or two first
@ -1641,10 +1638,10 @@ static int __init timer_irq_works(void)
* least one tick may be lost due to delays.
*/
/* jiffies wrap? */
if (time_after(jiffies, t1 + 4))
return 1;
return 0;
local_irq_disable();
/* Did jiffies advance? */
return time_after(jiffies, t1 + 4);
}
/*
@ -1696,13 +1693,13 @@ static bool io_apic_level_ack_pending(struct mp_chip_data *data)
raw_spin_lock_irqsave(&ioapic_lock, flags);
for_each_irq_pin(entry, data->irq_2_pin) {
unsigned int reg;
struct IO_APIC_route_entry e;
int pin;
pin = entry->pin;
reg = io_apic_read(entry->apic, 0x10 + pin*2);
e.w1 = io_apic_read(entry->apic, 0x10 + pin*2);
/* Is the remote IRR bit set? */
if (reg & IO_APIC_REDIR_REMOTE_IRR) {
if (e.irr) {
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return true;
}
@ -1849,21 +1846,62 @@ static void ioapic_ir_ack_level(struct irq_data *irq_data)
eoi_ioapic_pin(data->entry.vector, data);
}
/*
* The I/OAPIC is just a device for generating MSI messages from legacy
* interrupt pins. Various fields of the RTE translate into bits of the
* resulting MSI which had a historical meaning.
*
* With interrupt remapping, many of those bits have different meanings
* in the underlying MSI, but the way that the I/OAPIC transforms them
* from its RTE to the MSI message is the same. This function allows
* the parent IRQ domain to compose the MSI message, then takes the
* relevant bits to put them in the appropriate places in the RTE in
* order to generate that message when the IRQ happens.
*
* The setup here relies on a preconfigured route entry (is_level,
* active_low, masked) because the parent domain is merely composing the
* generic message routing information which is used for the MSI.
*/
static void ioapic_setup_msg_from_msi(struct irq_data *irq_data,
struct IO_APIC_route_entry *entry)
{
struct msi_msg msg;
/* Let the parent domain compose the MSI message */
irq_chip_compose_msi_msg(irq_data, &msg);
/*
* - Real vector
* - DMAR/IR: 8bit subhandle (ioapic.pin)
* - AMD/IR: 8bit IRTE index
*/
entry->vector = msg.arch_data.vector;
/* Delivery mode (for DMAR/IR all 0) */
entry->delivery_mode = msg.arch_data.delivery_mode;
/* Destination mode or DMAR/IR index bit 15 */
entry->dest_mode_logical = msg.arch_addr_lo.dest_mode_logical;
/* DMAR/IR: 1, 0 for all other modes */
entry->ir_format = msg.arch_addr_lo.dmar_format;
/*
* - DMAR/IR: index bit 0-14.
*
* - Virt: If the host supports x2apic without a virtualized IR
* unit then bit 0-6 of dmar_index_0_14 are providing bit
* 8-14 of the destination id.
*
* All other modes have bit 0-6 of dmar_index_0_14 cleared and the
* topmost 8 bits are destination id bit 0-7 (entry::destid_0_7).
*/
entry->ir_index_0_14 = msg.arch_addr_lo.dmar_index_0_14;
}
static void ioapic_configure_entry(struct irq_data *irqd)
{
struct mp_chip_data *mpd = irqd->chip_data;
struct irq_cfg *cfg = irqd_cfg(irqd);
struct irq_pin_list *entry;
/*
* Only update when the parent is the vector domain, don't touch it
* if the parent is the remapping domain. Check the installed
* ioapic chip to verify that.
*/
if (irqd->chip == &ioapic_chip) {
mpd->entry.dest = cfg->dest_apicid;
mpd->entry.vector = cfg->vector;
}
ioapic_setup_msg_from_msi(irqd, &mpd->entry);
for_each_irq_pin(entry, mpd->irq_2_pin)
__ioapic_write_entry(entry->apic, entry->pin, mpd->entry);
}
@ -1919,7 +1957,7 @@ static int ioapic_irq_get_chip_state(struct irq_data *irqd,
* irrelevant because the IO-APIC treats them as fire and
* forget.
*/
if (rentry.irr && rentry.trigger) {
if (rentry.irr && rentry.is_level) {
*state = true;
break;
}
@ -2027,6 +2065,7 @@ static inline void __init unlock_ExtINT_logic(void)
int apic, pin, i;
struct IO_APIC_route_entry entry0, entry1;
unsigned char save_control, save_freq_select;
u32 apic_id;
pin = find_isa_irq_pin(8, mp_INT);
if (pin == -1) {
@ -2042,14 +2081,16 @@ static inline void __init unlock_ExtINT_logic(void)
entry0 = ioapic_read_entry(apic, pin);
clear_IO_APIC_pin(apic, pin);
apic_id = hard_smp_processor_id();
memset(&entry1, 0, sizeof(entry1));
entry1.dest_mode = IOAPIC_DEST_MODE_PHYSICAL;
entry1.mask = IOAPIC_UNMASKED;
entry1.dest = hard_smp_processor_id();
entry1.delivery_mode = dest_ExtINT;
entry1.polarity = entry0.polarity;
entry1.trigger = IOAPIC_EDGE;
entry1.dest_mode_logical = true;
entry1.masked = false;
entry1.destid_0_7 = apic_id & 0xFF;
entry1.virt_destid_8_14 = apic_id >> 8;
entry1.delivery_mode = APIC_DELIVERY_MODE_EXTINT;
entry1.active_low = entry0.active_low;
entry1.is_level = false;
entry1.vector = 0;
ioapic_write_entry(apic, pin, entry1);
@ -2117,13 +2158,12 @@ static inline void __init check_timer(void)
struct irq_cfg *cfg = irqd_cfg(irq_data);
int node = cpu_to_node(0);
int apic1, pin1, apic2, pin2;
unsigned long flags;
int no_pin1 = 0;
if (!global_clock_event)
return;
local_irq_save(flags);
local_irq_disable();
/*
* get/set the timer IRQ vector:
@ -2178,9 +2218,9 @@ static inline void __init check_timer(void)
* so only need to unmask if it is level-trigger
* do we really have level trigger timer?
*/
int idx;
idx = find_irq_entry(apic1, pin1, mp_INT);
if (idx != -1 && irq_trigger(idx))
int idx = find_irq_entry(apic1, pin1, mp_INT);
if (idx != -1 && irq_is_level(idx))
unmask_ioapic_irq(irq_get_irq_data(0));
}
irq_domain_deactivate_irq(irq_data);
@ -2191,7 +2231,6 @@ static inline void __init check_timer(void)
goto out;
}
panic_if_irq_remap("timer doesn't work through Interrupt-remapped IO-APIC");
local_irq_disable();
clear_IO_APIC_pin(apic1, pin1);
if (!no_pin1)
apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: "
@ -2215,7 +2254,6 @@ static inline void __init check_timer(void)
/*
* Cleanup, just in case ...
*/
local_irq_disable();
legacy_pic->mask(0);
clear_IO_APIC_pin(apic2, pin2);
apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n");
@ -2232,7 +2270,6 @@ static inline void __init check_timer(void)
apic_printk(APIC_QUIET, KERN_INFO "..... works.\n");
goto out;
}
local_irq_disable();
legacy_pic->mask(0);
apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n");
@ -2251,7 +2288,6 @@ static inline void __init check_timer(void)
apic_printk(APIC_QUIET, KERN_INFO "..... works.\n");
goto out;
}
local_irq_disable();
apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n");
if (apic_is_x2apic_enabled())
apic_printk(APIC_QUIET, KERN_INFO
@ -2260,7 +2296,7 @@ static inline void __init check_timer(void)
panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a "
"report. Then try booting with the 'noapic' option.\n");
out:
local_irq_restore(flags);
local_irq_enable();
}
/*
@ -2284,36 +2320,37 @@ out:
static int mp_irqdomain_create(int ioapic)
{
struct irq_alloc_info info;
struct irq_domain *parent;
int hwirqs = mp_ioapic_pin_count(ioapic);
struct ioapic *ip = &ioapics[ioapic];
struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg;
struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic);
struct fwnode_handle *fn;
char *name = "IO-APIC";
struct irq_fwspec fwspec;
if (cfg->type == IOAPIC_DOMAIN_INVALID)
return 0;
init_irq_alloc_info(&info, NULL);
info.type = X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT;
info.devid = mpc_ioapic_id(ioapic);
parent = irq_remapping_get_irq_domain(&info);
if (!parent)
parent = x86_vector_domain;
else
name = "IO-APIC-IR";
/* Handle device tree enumerated APICs proper */
if (cfg->dev) {
fn = of_node_to_fwnode(cfg->dev);
} else {
fn = irq_domain_alloc_named_id_fwnode(name, ioapic);
fn = irq_domain_alloc_named_id_fwnode("IO-APIC", mpc_ioapic_id(ioapic));
if (!fn)
return -ENOMEM;
}
fwspec.fwnode = fn;
fwspec.param_count = 1;
fwspec.param[0] = mpc_ioapic_id(ioapic);
parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_ANY);
if (!parent) {
if (!cfg->dev)
irq_domain_free_fwnode(fn);
return -ENODEV;
}
ip->irqdomain = irq_domain_create_linear(fn, hwirqs, cfg->ops,
(void *)(long)ioapic);
@ -2587,30 +2624,6 @@ static int io_apic_get_version(int ioapic)
return reg_01.bits.version;
}
int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
{
int ioapic, pin, idx;
if (skip_ioapic_setup)
return -1;
ioapic = mp_find_ioapic(gsi);
if (ioapic < 0)
return -1;
pin = mp_find_ioapic_pin(ioapic, gsi);
if (pin < 0)
return -1;
idx = find_irq_entry(ioapic, pin, mp_INT);
if (idx < 0)
return -1;
*trigger = irq_trigger(idx);
*polarity = irq_polarity(idx);
return 0;
}
/*
* This function updates target affinity of IOAPIC interrupts to include
* the CPUs which came online during SMP bringup.
@ -2934,44 +2947,49 @@ static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data,
struct irq_alloc_info *info)
{
if (info && info->ioapic.valid) {
data->trigger = info->ioapic.trigger;
data->polarity = info->ioapic.polarity;
} else if (acpi_get_override_irq(gsi, &data->trigger,
&data->polarity) < 0) {
data->is_level = info->ioapic.is_level;
data->active_low = info->ioapic.active_low;
} else if (__acpi_get_override_irq(gsi, &data->is_level,
&data->active_low) < 0) {
/* PCI interrupts are always active low level triggered. */
data->trigger = IOAPIC_LEVEL;
data->polarity = IOAPIC_POL_LOW;
data->is_level = true;
data->active_low = true;
}
}
static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data,
struct IO_APIC_route_entry *entry)
/*
* Configure the I/O-APIC specific fields in the routing entry.
*
* This is important to setup the I/O-APIC specific bits (is_level,
* active_low, masked) because the underlying parent domain will only
* provide the routing information and is oblivious of the I/O-APIC
* specific bits.
*
* The entry is just preconfigured at this point and not written into the
* RTE. This happens later during activation which will fill in the actual
* routing information.
*/
static void mp_preconfigure_entry(struct mp_chip_data *data)
{
struct IO_APIC_route_entry *entry = &data->entry;
memset(entry, 0, sizeof(*entry));
entry->delivery_mode = apic->irq_delivery_mode;
entry->dest_mode = apic->irq_dest_mode;
entry->dest = cfg->dest_apicid;
entry->vector = cfg->vector;
entry->trigger = data->trigger;
entry->polarity = data->polarity;
entry->is_level = data->is_level;
entry->active_low = data->active_low;
/*
* Mask level triggered irqs. Edge triggered irqs are masked
* by the irq core code in case they fire.
*/
if (data->trigger == IOAPIC_LEVEL)
entry->mask = IOAPIC_MASKED;
else
entry->mask = IOAPIC_UNMASKED;
entry->masked = data->is_level;
}
int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
int ret, ioapic, pin;
struct irq_cfg *cfg;
struct irq_data *irq_data;
struct mp_chip_data *data;
struct irq_alloc_info *info = arg;
struct mp_chip_data *data;
struct irq_data *irq_data;
int ret, ioapic, pin;
unsigned long flags;
if (!info || nr_irqs > 1)
@ -2989,7 +3007,6 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
if (!data)
return -ENOMEM;
info->ioapic.entry = &data->entry;
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
if (ret < 0) {
kfree(data);
@ -3003,22 +3020,20 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
irq_data->chip_data = data;
mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
cfg = irqd_cfg(irq_data);
add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
mp_preconfigure_entry(data);
mp_register_handler(virq, data->is_level);
local_irq_save(flags);
if (info->ioapic.entry)
mp_setup_entry(cfg, data, info->ioapic.entry);
mp_register_handler(virq, data->trigger);
if (virq < nr_legacy_irqs())
legacy_pic->mask(virq);
local_irq_restore(flags);
apic_printk(APIC_VERBOSE, KERN_DEBUG
"IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n",
ioapic, mpc_ioapic_id(ioapic), pin, cfg->vector,
virq, data->trigger, data->polarity, cfg->dest_apicid);
"IOAPIC[%d]: Preconfigured routing entry (%d-%d -> IRQ %d Level:%i ActiveLow:%i)\n",
ioapic, mpc_ioapic_id(ioapic), pin, virq,
data->is_level, data->active_low);
return 0;
}

View File

@ -260,7 +260,7 @@ void default_send_IPI_mask_sequence_logical(const struct cpumask *mask,
for_each_cpu(query_cpu, mask)
__default_send_IPI_dest_field(
early_per_cpu(x86_cpu_to_logical_apicid, query_cpu),
vector, apic->dest_logical);
vector, APIC_DEST_LOGICAL);
local_irq_restore(flags);
}
@ -279,7 +279,7 @@ void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask,
continue;
__default_send_IPI_dest_field(
early_per_cpu(x86_cpu_to_logical_apicid, query_cpu),
vector, apic->dest_logical);
vector, APIC_DEST_LOGICAL);
}
local_irq_restore(flags);
}
@ -297,7 +297,7 @@ void default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector)
local_irq_save(flags);
WARN_ON(mask & ~cpumask_bits(cpu_online_mask)[0]);
__default_send_IPI_dest_field(mask, vector, apic->dest_logical);
__default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
local_irq_restore(flags);
}

View File

@ -15,7 +15,6 @@
#include <linux/hpet.h>
#include <linux/msi.h>
#include <asm/irqdomain.h>
#include <asm/msidef.h>
#include <asm/hpet.h>
#include <asm/hw_irq.h>
#include <asm/apic.h>
@ -23,38 +22,11 @@
struct irq_domain *x86_pci_msi_default_domain __ro_after_init;
static void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg)
{
msg->address_hi = MSI_ADDR_BASE_HI;
if (x2apic_enabled())
msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid);
msg->address_lo =
MSI_ADDR_BASE_LO |
((apic->irq_dest_mode == 0) ?
MSI_ADDR_DEST_MODE_PHYSICAL :
MSI_ADDR_DEST_MODE_LOGICAL) |
MSI_ADDR_REDIRECTION_CPU |
MSI_ADDR_DEST_ID(cfg->dest_apicid);
msg->data =
MSI_DATA_TRIGGER_EDGE |
MSI_DATA_LEVEL_ASSERT |
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR(cfg->vector);
}
void x86_vector_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
{
__irq_msi_compose_msg(irqd_cfg(data), msg);
}
static void irq_msi_update_msg(struct irq_data *irqd, struct irq_cfg *cfg)
{
struct msi_msg msg[2] = { [1] = { }, };
__irq_msi_compose_msg(cfg, msg);
__irq_msi_compose_msg(cfg, msg, false);
irq_data_get_irq_chip(irqd)->irq_write_msi_msg(irqd, msg);
}
@ -276,6 +248,17 @@ struct irq_domain *arch_create_remap_msi_irq_domain(struct irq_domain *parent,
#endif
#ifdef CONFIG_DMAR_TABLE
/*
* The Intel IOMMU (ab)uses the high bits of the MSI address to contain the
* high bits of the destination APIC ID. This can't be done in the general
* case for MSIs as it would be targeting real memory above 4GiB not the
* APIC.
*/
static void dmar_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
{
__irq_msi_compose_msg(irqd_cfg(data), msg, true);
}
static void dmar_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
{
dmar_msi_write(data->irq, msg);
@ -288,6 +271,7 @@ static struct irq_chip dmar_msi_controller = {
.irq_ack = irq_chip_ack_parent,
.irq_set_affinity = msi_domain_set_affinity,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_compose_msi_msg = dmar_msi_compose_msg,
.irq_write_msi_msg = dmar_msi_write_msg,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
@ -356,114 +340,3 @@ void dmar_free_hwirq(int irq)
irq_domain_free_irqs(irq, 1);
}
#endif
/*
* MSI message composition
*/
#ifdef CONFIG_HPET_TIMER
static inline int hpet_dev_id(struct irq_domain *domain)
{
struct msi_domain_info *info = msi_get_domain_info(domain);
return (int)(long)info->data;
}
static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
{
hpet_msi_write(irq_data_get_irq_handler_data(data), msg);
}
static struct irq_chip hpet_msi_controller __ro_after_init = {
.name = "HPET-MSI",
.irq_unmask = hpet_msi_unmask,
.irq_mask = hpet_msi_mask,
.irq_ack = irq_chip_ack_parent,
.irq_set_affinity = msi_domain_set_affinity,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_write_msi_msg = hpet_msi_write_msg,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
static int hpet_msi_init(struct irq_domain *domain,
struct msi_domain_info *info, unsigned int virq,
irq_hw_number_t hwirq, msi_alloc_info_t *arg)
{
irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
irq_domain_set_info(domain, virq, arg->hwirq, info->chip, NULL,
handle_edge_irq, arg->data, "edge");
return 0;
}
static void hpet_msi_free(struct irq_domain *domain,
struct msi_domain_info *info, unsigned int virq)
{
irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
}
static struct msi_domain_ops hpet_msi_domain_ops = {
.msi_init = hpet_msi_init,
.msi_free = hpet_msi_free,
};
static struct msi_domain_info hpet_msi_domain_info = {
.ops = &hpet_msi_domain_ops,
.chip = &hpet_msi_controller,
.flags = MSI_FLAG_USE_DEF_DOM_OPS,
};
struct irq_domain *hpet_create_irq_domain(int hpet_id)
{
struct msi_domain_info *domain_info;
struct irq_domain *parent, *d;
struct irq_alloc_info info;
struct fwnode_handle *fn;
if (x86_vector_domain == NULL)
return NULL;
domain_info = kzalloc(sizeof(*domain_info), GFP_KERNEL);
if (!domain_info)
return NULL;
*domain_info = hpet_msi_domain_info;
domain_info->data = (void *)(long)hpet_id;
init_irq_alloc_info(&info, NULL);
info.type = X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT;
info.devid = hpet_id;
parent = irq_remapping_get_irq_domain(&info);
if (parent == NULL)
parent = x86_vector_domain;
else
hpet_msi_controller.name = "IR-HPET-MSI";
fn = irq_domain_alloc_named_id_fwnode(hpet_msi_controller.name,
hpet_id);
if (!fn) {
kfree(domain_info);
return NULL;
}
d = msi_create_irq_domain(fn, domain_info, parent);
if (!d) {
irq_domain_free_fwnode(fn);
kfree(domain_info);
}
return d;
}
int hpet_assign_irq(struct irq_domain *domain, struct hpet_channel *hc,
int dev_num)
{
struct irq_alloc_info info;
init_irq_alloc_info(&info, NULL);
info.type = X86_IRQ_ALLOC_TYPE_HPET;
info.data = hc;
info.devid = hpet_dev_id(domain);
info.hwirq = dev_num;
return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &info);
}
#endif

View File

@ -69,16 +69,13 @@ static struct apic apic_default __ro_after_init = {
.apic_id_valid = default_apic_id_valid,
.apic_id_registered = default_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
/* logical delivery broadcast to all CPUs: */
.irq_dest_mode = 1,
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = true,
.disable_esr = 0,
.dest_logical = APIC_DEST_LOGICAL,
.check_apicid_used = default_check_apicid_used,
.init_apic_ldr = default_init_apic_ldr,
.ioapic_phys_id_map = default_ioapic_phys_id_map,
.setup_apic_routing = setup_apic_flat_routing,
.cpu_present_to_apicid = default_cpu_present_to_apicid,

View File

@ -640,7 +640,50 @@ static void x86_vector_debug_show(struct seq_file *m, struct irq_domain *d,
}
#endif
int x86_fwspec_is_ioapic(struct irq_fwspec *fwspec)
{
if (fwspec->param_count != 1)
return 0;
if (is_fwnode_irqchip(fwspec->fwnode)) {
const char *fwname = fwnode_get_name(fwspec->fwnode);
return fwname && !strncmp(fwname, "IO-APIC-", 8) &&
simple_strtol(fwname+8, NULL, 10) == fwspec->param[0];
}
return to_of_node(fwspec->fwnode) &&
of_device_is_compatible(to_of_node(fwspec->fwnode),
"intel,ce4100-ioapic");
}
int x86_fwspec_is_hpet(struct irq_fwspec *fwspec)
{
if (fwspec->param_count != 1)
return 0;
if (is_fwnode_irqchip(fwspec->fwnode)) {
const char *fwname = fwnode_get_name(fwspec->fwnode);
return fwname && !strncmp(fwname, "HPET-MSI-", 9) &&
simple_strtol(fwname+9, NULL, 10) == fwspec->param[0];
}
return 0;
}
static int x86_vector_select(struct irq_domain *d, struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token)
{
/*
* HPET and I/OAPIC cannot be parented in the vector domain
* if IRQ remapping is enabled. APIC IDs above 15 bits are
* only permitted if IRQ remapping is enabled, so check that.
*/
if (apic->apic_id_valid(32768))
return 0;
return x86_fwspec_is_ioapic(fwspec) || x86_fwspec_is_hpet(fwspec);
}
static const struct irq_domain_ops x86_vector_domain_ops = {
.select = x86_vector_select,
.alloc = x86_vector_alloc_irqs,
.free = x86_vector_free_irqs,
.activate = x86_vector_activate,
@ -822,6 +865,12 @@ void apic_ack_edge(struct irq_data *irqd)
apic_ack_irq(irqd);
}
static void x86_vector_msi_compose_msg(struct irq_data *data,
struct msi_msg *msg)
{
__irq_msi_compose_msg(irqd_cfg(data), msg, false);
}
static struct irq_chip lapic_controller = {
.name = "APIC",
.irq_ack = apic_ack_edge,

View File

@ -61,7 +61,7 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
if (!dest)
continue;
__x2apic_send_IPI_dest(dest, vector, apic->dest_logical);
__x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
/* Remove cluster CPUs from tmpmask */
cpumask_andnot(tmpmsk, tmpmsk, &cmsk->mask);
}
@ -184,15 +184,13 @@ static struct apic apic_x2apic_cluster __ro_after_init = {
.apic_id_valid = x2apic_apic_id_valid,
.apic_id_registered = x2apic_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
.irq_dest_mode = 1, /* logical */
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = true,
.disable_esr = 0,
.dest_logical = APIC_DEST_LOGICAL,
.check_apicid_used = NULL,
.init_apic_ldr = init_x2apic_ldr,
.ioapic_phys_id_map = NULL,
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,

View File

@ -8,6 +8,12 @@
int x2apic_phys;
static struct apic apic_x2apic_phys;
static u32 x2apic_max_apicid __ro_after_init;
void __init x2apic_set_max_apicid(u32 apicid)
{
x2apic_max_apicid = apicid;
}
static int __init set_x2apic_phys_mode(char *arg)
{
@ -98,6 +104,9 @@ static int x2apic_phys_probe(void)
/* Common x2apic functions, also used by x2apic_cluster */
int x2apic_apic_id_valid(u32 apicid)
{
if (x2apic_max_apicid && apicid > x2apic_max_apicid)
return 0;
return 1;
}
@ -148,15 +157,13 @@ static struct apic apic_x2apic_phys __ro_after_init = {
.apic_id_valid = x2apic_apic_id_valid,
.apic_id_registered = x2apic_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
.irq_dest_mode = 0, /* physical */
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = false,
.disable_esr = 0,
.dest_logical = 0,
.check_apicid_used = NULL,
.init_apic_ldr = init_x2apic_ldr,
.ioapic_phys_id_map = NULL,
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,

View File

@ -728,9 +728,9 @@ static void uv_send_IPI_one(int cpu, int vector)
unsigned long dmode, val;
if (vector == NMI_VECTOR)
dmode = dest_NMI;
dmode = APIC_DELIVERY_MODE_NMI;
else
dmode = dest_Fixed;
dmode = APIC_DELIVERY_MODE_FIXED;
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
(apicid << UVH_IPI_INT_APIC_ID_SHFT) |
@ -832,15 +832,13 @@ static struct apic apic_x2apic_uv_x __ro_after_init = {
.apic_id_valid = uv_apic_id_valid,
.apic_id_registered = uv_apic_id_registered,
.irq_delivery_mode = dest_Fixed,
.irq_dest_mode = 0, /* Physical */
.delivery_mode = APIC_DELIVERY_MODE_FIXED,
.dest_mode_logical = false,
.disable_esr = 0,
.dest_logical = APIC_DEST_LOGICAL,
.check_apicid_used = NULL,
.init_apic_ldr = uv_init_apic_ldr,
.ioapic_phys_id_map = NULL,
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,

View File

@ -366,9 +366,38 @@ static void __init ms_hyperv_init_platform(void)
#endif
}
static bool __init ms_hyperv_x2apic_available(void)
{
return x2apic_supported();
}
/*
* If ms_hyperv_msi_ext_dest_id() returns true, hyperv_prepare_irq_remapping()
* returns -ENODEV and the Hyper-V IOMMU driver is not used; instead, the
* generic support of the 15-bit APIC ID is used: see __irq_msi_compose_msg().
*
* Note: for a VM on Hyper-V, the I/O-APIC is the only device which
* (logically) generates MSIs directly to the system APIC irq domain.
* There is no HPET, and PCI MSI/MSI-X interrupts are remapped by the
* pci-hyperv host bridge.
*/
static bool __init ms_hyperv_msi_ext_dest_id(void)
{
u32 eax;
eax = cpuid_eax(HYPERV_CPUID_VIRT_STACK_INTERFACE);
if (eax != HYPERV_VS_INTERFACE_EAX_SIGNATURE)
return false;
eax = cpuid_eax(HYPERV_CPUID_VIRT_STACK_PROPERTIES);
return eax & HYPERV_VS_PROPERTIES_EAX_EXTENDED_IOAPIC_RTE;
}
const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
.name = "Microsoft Hyper-V",
.detect = ms_hyperv_platform,
.type = X86_HYPER_MS_HYPERV,
.init.x2apic_available = ms_hyperv_x2apic_available,
.init.msi_ext_dest_id = ms_hyperv_msi_ext_dest_id,
.init.init_platform = ms_hyperv_init_platform,
};

View File

@ -184,31 +184,31 @@ static unsigned int ioapic_id;
struct of_ioapic_type {
u32 out_type;
u32 trigger;
u32 polarity;
u32 is_level;
u32 active_low;
};
static struct of_ioapic_type of_ioapic_type[] =
{
{
.out_type = IRQ_TYPE_EDGE_RISING,
.trigger = IOAPIC_EDGE,
.polarity = 1,
},
{
.out_type = IRQ_TYPE_LEVEL_LOW,
.trigger = IOAPIC_LEVEL,
.polarity = 0,
.out_type = IRQ_TYPE_EDGE_FALLING,
.is_level = 0,
.active_low = 1,
},
{
.out_type = IRQ_TYPE_LEVEL_HIGH,
.trigger = IOAPIC_LEVEL,
.polarity = 1,
.is_level = 1,
.active_low = 0,
},
{
.out_type = IRQ_TYPE_EDGE_FALLING,
.trigger = IOAPIC_EDGE,
.polarity = 0,
.out_type = IRQ_TYPE_LEVEL_LOW,
.is_level = 1,
.active_low = 1,
},
{
.out_type = IRQ_TYPE_EDGE_RISING,
.is_level = 0,
.active_low = 0,
},
};
@ -228,7 +228,7 @@ static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
return -EINVAL;
it = &of_ioapic_type[type_index];
ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity);
ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->is_level, it->active_low);
tmp.devid = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
tmp.ioapic.pin = fwspec->param[0];

View File

@ -7,6 +7,7 @@
#include <linux/cpu.h>
#include <linux/irq.h>
#include <asm/irq_remapping.h>
#include <asm/hpet.h>
#include <asm/time.h>
@ -50,7 +51,7 @@ unsigned long hpet_address;
u8 hpet_blockid; /* OS timer block num */
bool hpet_msi_disable;
#ifdef CONFIG_PCI_MSI
#ifdef CONFIG_GENERIC_MSI_IRQ
static DEFINE_PER_CPU(struct hpet_channel *, cpu_hpet_channel);
static struct irq_domain *hpet_domain;
#endif
@ -467,9 +468,8 @@ static void __init hpet_legacy_clockevent_register(struct hpet_channel *hc)
/*
* HPET MSI Support
*/
#ifdef CONFIG_PCI_MSI
void hpet_msi_unmask(struct irq_data *data)
#ifdef CONFIG_GENERIC_MSI_IRQ
static void hpet_msi_unmask(struct irq_data *data)
{
struct hpet_channel *hc = irq_data_get_irq_handler_data(data);
unsigned int cfg;
@ -479,7 +479,7 @@ void hpet_msi_unmask(struct irq_data *data)
hpet_writel(cfg, HPET_Tn_CFG(hc->num));
}
void hpet_msi_mask(struct irq_data *data)
static void hpet_msi_mask(struct irq_data *data)
{
struct hpet_channel *hc = irq_data_get_irq_handler_data(data);
unsigned int cfg;
@ -489,12 +489,122 @@ void hpet_msi_mask(struct irq_data *data)
hpet_writel(cfg, HPET_Tn_CFG(hc->num));
}
void hpet_msi_write(struct hpet_channel *hc, struct msi_msg *msg)
static void hpet_msi_write(struct hpet_channel *hc, struct msi_msg *msg)
{
hpet_writel(msg->data, HPET_Tn_ROUTE(hc->num));
hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hc->num) + 4);
}
static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
{
hpet_msi_write(irq_data_get_irq_handler_data(data), msg);
}
static struct irq_chip hpet_msi_controller __ro_after_init = {
.name = "HPET-MSI",
.irq_unmask = hpet_msi_unmask,
.irq_mask = hpet_msi_mask,
.irq_ack = irq_chip_ack_parent,
.irq_set_affinity = msi_domain_set_affinity,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_write_msi_msg = hpet_msi_write_msg,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
static int hpet_msi_init(struct irq_domain *domain,
struct msi_domain_info *info, unsigned int virq,
irq_hw_number_t hwirq, msi_alloc_info_t *arg)
{
irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
irq_domain_set_info(domain, virq, arg->hwirq, info->chip, NULL,
handle_edge_irq, arg->data, "edge");
return 0;
}
static void hpet_msi_free(struct irq_domain *domain,
struct msi_domain_info *info, unsigned int virq)
{
irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
}
static struct msi_domain_ops hpet_msi_domain_ops = {
.msi_init = hpet_msi_init,
.msi_free = hpet_msi_free,
};
static struct msi_domain_info hpet_msi_domain_info = {
.ops = &hpet_msi_domain_ops,
.chip = &hpet_msi_controller,
.flags = MSI_FLAG_USE_DEF_DOM_OPS,
};
static struct irq_domain *hpet_create_irq_domain(int hpet_id)
{
struct msi_domain_info *domain_info;
struct irq_domain *parent, *d;
struct fwnode_handle *fn;
struct irq_fwspec fwspec;
if (x86_vector_domain == NULL)
return NULL;
domain_info = kzalloc(sizeof(*domain_info), GFP_KERNEL);
if (!domain_info)
return NULL;
*domain_info = hpet_msi_domain_info;
domain_info->data = (void *)(long)hpet_id;
fn = irq_domain_alloc_named_id_fwnode(hpet_msi_controller.name,
hpet_id);
if (!fn) {
kfree(domain_info);
return NULL;
}
fwspec.fwnode = fn;
fwspec.param_count = 1;
fwspec.param[0] = hpet_id;
parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_ANY);
if (!parent) {
irq_domain_free_fwnode(fn);
kfree(domain_info);
return NULL;
}
if (parent != x86_vector_domain)
hpet_msi_controller.name = "IR-HPET-MSI";
d = msi_create_irq_domain(fn, domain_info, parent);
if (!d) {
irq_domain_free_fwnode(fn);
kfree(domain_info);
}
return d;
}
static inline int hpet_dev_id(struct irq_domain *domain)
{
struct msi_domain_info *info = msi_get_domain_info(domain);
return (int)(long)info->data;
}
static int hpet_assign_irq(struct irq_domain *domain, struct hpet_channel *hc,
int dev_num)
{
struct irq_alloc_info info;
init_irq_alloc_info(&info, NULL);
info.type = X86_IRQ_ALLOC_TYPE_HPET;
info.data = hc;
info.devid = hpet_dev_id(domain);
info.hwirq = dev_num;
return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &info);
}
static int hpet_clkevt_msi_resume(struct clock_event_device *evt)
{
struct hpet_channel *hc = clockevent_to_channel(evt);

View File

@ -740,6 +740,11 @@ static void __init kvm_apic_init(void)
#endif
}
static bool __init kvm_msi_ext_dest_id(void)
{
return kvm_para_has_feature(KVM_FEATURE_MSI_EXT_DEST_ID);
}
static void __init kvm_init_platform(void)
{
kvmclock_init();
@ -769,6 +774,7 @@ const __initconst struct hypervisor_x86 x86_hyper_kvm = {
.type = X86_HYPER_KVM,
.init.guest_late_init = kvm_guest_init,
.init.x2apic_available = kvm_para_available,
.init.msi_ext_dest_id = kvm_msi_ext_dest_id,
.init.init_platform = kvm_init_platform,
#if defined(CONFIG_AMD_MEM_ENCRYPT)
.runtime.sev_es_hcall_prepare = kvm_sev_es_hcall_prepare,

View File

@ -752,13 +752,14 @@ static void __init smp_quirk_init_udelay(void)
int
wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip)
{
u32 dm = apic->dest_mode_logical ? APIC_DEST_LOGICAL : APIC_DEST_PHYSICAL;
unsigned long send_status, accept_status = 0;
int maxlvt;
/* Target chip */
/* Boot on the stack */
/* Kick the second */
apic_icr_write(APIC_DM_NMI | apic->dest_logical, apicid);
apic_icr_write(APIC_DM_NMI | dm, apicid);
pr_debug("Waiting for send to finish...\n");
send_status = safe_apic_wait_icr_idle();
@ -985,10 +986,7 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
if (!boot_error) {
enable_start_cpu0 = 1;
*cpu0_nmi_registered = 1;
if (apic->dest_logical == APIC_DEST_LOGICAL)
id = cpu0_logical_apicid;
else
id = apicid;
id = apic->dest_mode_logical ? cpu0_logical_apicid : apicid;
boot_error = wakeup_secondary_cpu_via_nmi(id, start_ip);
}

View File

@ -110,6 +110,7 @@ struct x86_init_ops x86_init __initdata = {
.init_platform = x86_init_noop,
.guest_late_init = x86_init_noop,
.x2apic_available = bool_x86_init_noop,
.msi_ext_dest_id = bool_x86_init_noop,
.init_mem_mapping = x86_init_noop,
.init_after_bootmem = x86_init_noop,
},

View File

@ -16,8 +16,6 @@
#include <trace/events/kvm.h>
#include <asm/msidef.h>
#include "irq.h"
#include "ioapic.h"
@ -104,22 +102,19 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
void kvm_set_msi_irq(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e,
struct kvm_lapic_irq *irq)
{
trace_kvm_msi_set_irq(e->msi.address_lo | (kvm->arch.x2apic_format ?
(u64)e->msi.address_hi << 32 : 0),
e->msi.data);
struct msi_msg msg = { .address_lo = e->msi.address_lo,
.address_hi = e->msi.address_hi,
.data = e->msi.data };
irq->dest_id = (e->msi.address_lo &
MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
if (kvm->arch.x2apic_format)
irq->dest_id |= MSI_ADDR_EXT_DEST_ID(e->msi.address_hi);
irq->vector = (e->msi.data &
MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
irq->dest_mode = kvm_lapic_irq_dest_mode(
!!((1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo));
irq->trig_mode = (1 << MSI_DATA_TRIGGER_SHIFT) & e->msi.data;
irq->delivery_mode = e->msi.data & 0x700;
irq->msi_redir_hint = ((e->msi.address_lo
& MSI_ADDR_REDIRECTION_LOWPRI) > 0);
trace_kvm_msi_set_irq(msg.address_lo | (kvm->arch.x2apic_format ?
(u64)msg.address_hi << 32 : 0), msg.data);
irq->dest_id = x86_msi_msg_get_destid(&msg, kvm->arch.x2apic_format);
irq->vector = msg.arch_data.vector;
irq->dest_mode = kvm_lapic_irq_dest_mode(msg.arch_addr_lo.dest_mode_logical);
irq->trig_mode = msg.arch_data.is_level;
irq->delivery_mode = msg.arch_data.delivery_mode << 8;
irq->msi_redir_hint = msg.arch_addr_lo.redirect_hint;
irq->level = 1;
irq->shorthand = APIC_DEST_NOSHORT;
}

View File

@ -215,7 +215,7 @@ static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
static int intel_mid_pci_irq_enable(struct pci_dev *dev)
{
struct irq_alloc_info info;
int polarity;
bool polarity_low;
int ret;
u8 gsi;
@ -230,7 +230,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
switch (intel_mid_identify_cpu()) {
case INTEL_MID_CPU_CHIP_TANGIER:
polarity = IOAPIC_POL_HIGH;
polarity_low = false;
/* Special treatment for IRQ0 */
if (gsi == 0) {
@ -252,11 +252,11 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
}
break;
default:
polarity = IOAPIC_POL_LOW;
polarity_low = true;
break;
}
ioapic_set_alloc_attr(&info, dev_to_node(&dev->dev), 1, polarity);
ioapic_set_alloc_attr(&info, dev_to_node(&dev->dev), 1, polarity_low);
/*
* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to

View File

@ -152,7 +152,6 @@ static int acpi_register_gsi_xen(struct device *dev, u32 gsi,
#if defined(CONFIG_PCI_MSI)
#include <linux/msi.h>
#include <asm/msidef.h>
struct xen_pci_frontend_ops *xen_pci_frontend;
EXPORT_SYMBOL_GPL(xen_pci_frontend);
@ -210,23 +209,20 @@ free:
return ret;
}
#define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \
MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0))
static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
struct msi_msg *msg)
{
/* We set vector == 0 to tell the hypervisor we don't care about it,
* but we want a pirq setup instead.
* We use the dest_id field to pass the pirq that we want. */
msg->address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(pirq);
msg->address_lo =
MSI_ADDR_BASE_LO |
MSI_ADDR_DEST_MODE_PHYSICAL |
MSI_ADDR_REDIRECTION_CPU |
MSI_ADDR_DEST_ID(pirq);
msg->data = XEN_PIRQ_MSI_DATA;
/*
* We set vector == 0 to tell the hypervisor we don't care about
* it, but we want a pirq setup instead. We use the dest_id fields
* to pass the pirq that we want.
*/
memset(msg, 0, sizeof(*msg));
msg->address_hi = X86_MSI_BASE_ADDRESS_HIGH;
msg->arch_addr_hi.destid_8_31 = pirq >> 8;
msg->arch_addr_lo.destid_0_7 = pirq & 0xFF;
msg->arch_addr_lo.base_address = X86_MSI_BASE_ADDRESS_LOW;
msg->arch_data.delivery_mode = APIC_DELIVERY_MODE_EXTINT;
}
static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)

View File

@ -35,8 +35,8 @@ static void uv_program_mmr(struct irq_cfg *cfg, struct uv_irq_2_mmr_pnode *info)
mmr_value = 0;
entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
entry->vector = cfg->vector;
entry->delivery_mode = apic->irq_delivery_mode;
entry->dest_mode = apic->irq_dest_mode;
entry->delivery_mode = apic->delivery_mode;
entry->dest_mode = apic->dest_mode_logical;
entry->polarity = 0;
entry->trigger = 0;
entry->mask = 0;

View File

@ -148,15 +148,12 @@ static struct apic xen_pv_apic = {
.apic_id_valid = xen_id_always_valid,
.apic_id_registered = xen_id_always_registered,
/* .irq_delivery_mode - used in native_compose_msi_msg only */
/* .irq_dest_mode - used in native_compose_msi_msg only */
/* .delivery_mode and .dest_mode_logical not used by XENPV */
.disable_esr = 0,
/* .dest_logical - default_send_IPI_ use it but we use our own. */
.check_apicid_used = default_check_apicid_used, /* Used on 32-bit */
.init_apic_ldr = xen_noop, /* setup_local_APIC calls it */
.ioapic_phys_id_map = default_ioapic_phys_id_map, /* Used on 32-bit */
.setup_apic_routing = NULL,
.cpu_present_to_apicid = xen_cpu_present_to_apicid,

View File

@ -897,7 +897,7 @@ struct amd_ir_data {
};
struct amd_irte_ops {
void (*prepare)(void *, u32, u32, u8, u32, int);
void (*prepare)(void *, u32, bool, u8, u32, int);
void (*activate)(void *, u16, u16);
void (*deactivate)(void *, u16, u16);
void (*set_affinity)(void *, u16, u16, u8, u32);

View File

@ -16,6 +16,7 @@
#include <linux/syscore_ops.h>
#include <linux/interrupt.h>
#include <linux/msi.h>
#include <linux/irq.h>
#include <linux/amd-iommu.h>
#include <linux/export.h>
#include <linux/kmemleak.h>
@ -23,7 +24,6 @@
#include <asm/pci-direct.h>
#include <asm/iommu.h>
#include <asm/apic.h>
#include <asm/msidef.h>
#include <asm/gart.h>
#include <asm/x86_init.h>
#include <asm/iommu_table.h>
@ -1575,14 +1575,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
break;
}
/*
* Note: Since iommu_update_intcapxt() leverages
* the IOMMU MMIO access to MSI capability block registers
* for MSI address lo/hi/data, we need to check both
* EFR[XtSup] and EFR[MsiCapMmioSup] for x2APIC support.
*/
if ((h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT)) &&
(h->efr_reg & BIT(IOMMU_EFR_MSICAPMMIOSUP_SHIFT)))
if (h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT))
amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE;
break;
default:
@ -1619,9 +1612,11 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
if (ret)
return ret;
ret = amd_iommu_create_irq_domain(iommu);
if (ret)
return ret;
if (amd_iommu_irq_remap) {
ret = amd_iommu_create_irq_domain(iommu);
if (ret)
return ret;
}
/*
* Make sure IOMMU is not considered to translate itself. The IVRS
@ -1983,98 +1978,190 @@ static int iommu_setup_msi(struct amd_iommu *iommu)
return 0;
}
#define XT_INT_DEST_MODE(x) (((x) & 0x1ULL) << 2)
#define XT_INT_DEST_LO(x) (((x) & 0xFFFFFFULL) << 8)
#define XT_INT_VEC(x) (((x) & 0xFFULL) << 32)
#define XT_INT_DEST_HI(x) ((((x) >> 24) & 0xFFULL) << 56)
union intcapxt {
u64 capxt;
struct {
u64 reserved_0 : 2,
dest_mode_logical : 1,
reserved_1 : 5,
destid_0_23 : 24,
vector : 8,
reserved_2 : 16,
destid_24_31 : 8;
};
} __attribute__ ((packed));
/*
* Setup the IntCapXT registers with interrupt routing information
* based on the PCI MSI capability block registers, accessed via
* MMIO MSI address low/hi and MSI data registers.
* There isn't really any need to mask/unmask at the irqchip level because
* the 64-bit INTCAPXT registers can be updated atomically without tearing
* when the affinity is being updated.
*/
static void iommu_update_intcapxt(struct amd_iommu *iommu)
static void intcapxt_unmask_irq(struct irq_data *data)
{
u64 val;
u32 addr_lo = readl(iommu->mmio_base + MMIO_MSI_ADDR_LO_OFFSET);
u32 addr_hi = readl(iommu->mmio_base + MMIO_MSI_ADDR_HI_OFFSET);
u32 data = readl(iommu->mmio_base + MMIO_MSI_DATA_OFFSET);
bool dm = (addr_lo >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
u32 dest = ((addr_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xFF);
}
if (x2apic_enabled())
dest |= MSI_ADDR_EXT_DEST_ID(addr_hi);
static void intcapxt_mask_irq(struct irq_data *data)
{
}
val = XT_INT_VEC(data & 0xFF) |
XT_INT_DEST_MODE(dm) |
XT_INT_DEST_LO(dest) |
XT_INT_DEST_HI(dest);
static struct irq_chip intcapxt_controller;
static int intcapxt_irqdomain_activate(struct irq_domain *domain,
struct irq_data *irqd, bool reserve)
{
struct amd_iommu *iommu = irqd->chip_data;
struct irq_cfg *cfg = irqd_cfg(irqd);
union intcapxt xt;
xt.capxt = 0ULL;
xt.dest_mode_logical = apic->dest_mode_logical;
xt.vector = cfg->vector;
xt.destid_0_23 = cfg->dest_apicid & GENMASK(23, 0);
xt.destid_24_31 = cfg->dest_apicid >> 24;
/**
* Current IOMMU implemtation uses the same IRQ for all
* 3 IOMMU interrupts.
*/
writeq(val, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET);
writeq(val, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET);
writeq(val, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET);
writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET);
writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET);
writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET);
return 0;
}
static void _irq_notifier_notify(struct irq_affinity_notify *notify,
const cpumask_t *mask)
static void intcapxt_irqdomain_deactivate(struct irq_domain *domain,
struct irq_data *irqd)
{
struct amd_iommu *iommu;
for_each_iommu(iommu) {
if (iommu->dev->irq == notify->irq) {
iommu_update_intcapxt(iommu);
break;
}
}
intcapxt_mask_irq(irqd);
}
static void _irq_notifier_release(struct kref *ref)
static int intcapxt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
}
struct irq_alloc_info *info = arg;
int i, ret;
static int iommu_init_intcapxt(struct amd_iommu *iommu)
{
int ret;
struct irq_affinity_notify *notify = &iommu->intcapxt_notify;
if (!info || info->type != X86_IRQ_ALLOC_TYPE_AMDVI)
return -EINVAL;
/**
* IntCapXT requires XTSup=1 and MsiCapMmioSup=1,
* which can be inferred from amd_iommu_xt_mode.
*/
if (amd_iommu_xt_mode != IRQ_REMAP_X2APIC_MODE)
return 0;
/**
* Also, we need to setup notifier to update the IntCapXT registers
* whenever the irq affinity is changed from user-space.
*/
notify->irq = iommu->dev->irq;
notify->notify = _irq_notifier_notify,
notify->release = _irq_notifier_release,
ret = irq_set_affinity_notifier(iommu->dev->irq, notify);
if (ret) {
pr_err("Failed to register irq affinity notifier (devid=%#x, irq %d)\n",
iommu->devid, iommu->dev->irq);
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
if (ret < 0)
return ret;
for (i = virq; i < virq + nr_irqs; i++) {
struct irq_data *irqd = irq_domain_get_irq_data(domain, i);
irqd->chip = &intcapxt_controller;
irqd->chip_data = info->data;
__irq_set_handler(i, handle_edge_irq, 0, "edge");
}
iommu_update_intcapxt(iommu);
iommu_feature_enable(iommu, CONTROL_INTCAPXT_EN);
return ret;
}
static int iommu_init_msi(struct amd_iommu *iommu)
static void intcapxt_irqdomain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs)
{
irq_domain_free_irqs_top(domain, virq, nr_irqs);
}
static int intcapxt_set_affinity(struct irq_data *irqd,
const struct cpumask *mask, bool force)
{
struct irq_data *parent = irqd->parent_data;
int ret;
ret = parent->chip->irq_set_affinity(parent, mask, force);
if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
return ret;
return intcapxt_irqdomain_activate(irqd->domain, irqd, false);
}
static struct irq_chip intcapxt_controller = {
.name = "IOMMU-MSI",
.irq_unmask = intcapxt_unmask_irq,
.irq_mask = intcapxt_mask_irq,
.irq_ack = irq_chip_ack_parent,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_set_affinity = intcapxt_set_affinity,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
static const struct irq_domain_ops intcapxt_domain_ops = {
.alloc = intcapxt_irqdomain_alloc,
.free = intcapxt_irqdomain_free,
.activate = intcapxt_irqdomain_activate,
.deactivate = intcapxt_irqdomain_deactivate,
};
static struct irq_domain *iommu_irqdomain;
static struct irq_domain *iommu_get_irqdomain(void)
{
struct fwnode_handle *fn;
/* No need for locking here (yet) as the init is single-threaded */
if (iommu_irqdomain)
return iommu_irqdomain;
fn = irq_domain_alloc_named_fwnode("AMD-Vi-MSI");
if (!fn)
return NULL;
iommu_irqdomain = irq_domain_create_hierarchy(x86_vector_domain, 0, 0,
fn, &intcapxt_domain_ops,
NULL);
if (!iommu_irqdomain)
irq_domain_free_fwnode(fn);
return iommu_irqdomain;
}
static int iommu_setup_intcapxt(struct amd_iommu *iommu)
{
struct irq_domain *domain;
struct irq_alloc_info info;
int irq, ret;
domain = iommu_get_irqdomain();
if (!domain)
return -ENXIO;
init_irq_alloc_info(&info, NULL);
info.type = X86_IRQ_ALLOC_TYPE_AMDVI;
info.data = iommu;
irq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &info);
if (irq < 0) {
irq_domain_remove(domain);
return irq;
}
ret = request_threaded_irq(irq, amd_iommu_int_handler,
amd_iommu_int_thread, 0, "AMD-Vi", iommu);
if (ret) {
irq_domain_free_irqs(irq, 1);
irq_domain_remove(domain);
return ret;
}
iommu_feature_enable(iommu, CONTROL_INTCAPXT_EN);
return 0;
}
static int iommu_init_irq(struct amd_iommu *iommu)
{
int ret;
if (iommu->int_enabled)
goto enable_faults;
if (iommu->dev->msi_cap)
if (amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE)
ret = iommu_setup_intcapxt(iommu);
else if (iommu->dev->msi_cap)
ret = iommu_setup_msi(iommu);
else
ret = -ENODEV;
@ -2083,10 +2170,6 @@ static int iommu_init_msi(struct amd_iommu *iommu)
return ret;
enable_faults:
ret = iommu_init_intcapxt(iommu);
if (ret)
return ret;
iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
if (iommu->ppr_log != NULL)
@ -2709,7 +2792,7 @@ static int amd_iommu_enable_interrupts(void)
int ret = 0;
for_each_iommu(iommu) {
ret = iommu_init_msi(iommu);
ret = iommu_init_irq(iommu);
if (ret)
goto out;
}

View File

@ -35,7 +35,6 @@
#include <asm/io_apic.h>
#include <asm/apic.h>
#include <asm/hw_irq.h>
#include <asm/msidef.h>
#include <asm/proto.h>
#include <asm/iommu.h>
#include <asm/gart.h>
@ -3466,7 +3465,7 @@ static void free_irte(u16 devid, int index)
}
static void irte_prepare(void *entry,
u32 delivery_mode, u32 dest_mode,
u32 delivery_mode, bool dest_mode,
u8 vector, u32 dest_apicid, int devid)
{
union irte *irte = (union irte *) entry;
@ -3480,7 +3479,7 @@ static void irte_prepare(void *entry,
}
static void irte_ga_prepare(void *entry,
u32 delivery_mode, u32 dest_mode,
u32 delivery_mode, bool dest_mode,
u8 vector, u32 dest_apicid, int devid)
{
struct irte_ga *irte = (struct irte_ga *) entry;
@ -3602,10 +3601,8 @@ static int get_devid(struct irq_alloc_info *info)
{
switch (info->type) {
case X86_IRQ_ALLOC_TYPE_IOAPIC:
case X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT:
return get_ioapic_devid(info->devid);
case X86_IRQ_ALLOC_TYPE_HPET:
case X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT:
return get_hpet_devid(info->devid);
case X86_IRQ_ALLOC_TYPE_PCI_MSI:
case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
@ -3616,54 +3613,28 @@ static int get_devid(struct irq_alloc_info *info)
}
}
static struct irq_domain *get_irq_domain_for_devid(struct irq_alloc_info *info,
int devid)
{
struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
if (!iommu)
return NULL;
switch (info->type) {
case X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT:
case X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT:
return iommu->ir_domain;
default:
WARN_ON_ONCE(1);
return NULL;
}
}
static struct irq_domain *get_irq_domain(struct irq_alloc_info *info)
{
int devid;
if (!info)
return NULL;
devid = get_devid(info);
if (devid < 0)
return NULL;
return get_irq_domain_for_devid(info, devid);
}
struct irq_remap_ops amd_iommu_irq_ops = {
.prepare = amd_iommu_prepare,
.enable = amd_iommu_enable,
.disable = amd_iommu_disable,
.reenable = amd_iommu_reenable,
.enable_faulting = amd_iommu_enable_faulting,
.get_irq_domain = get_irq_domain,
};
static void fill_msi_msg(struct msi_msg *msg, u32 index)
{
msg->data = index;
msg->address_lo = 0;
msg->arch_addr_lo.base_address = X86_MSI_BASE_ADDRESS_LOW;
msg->address_hi = X86_MSI_BASE_ADDRESS_HIGH;
}
static void irq_remapping_prepare_irte(struct amd_ir_data *data,
struct irq_cfg *irq_cfg,
struct irq_alloc_info *info,
int devid, int index, int sub_handle)
{
struct irq_2_irte *irte_info = &data->irq_2_irte;
struct msi_msg *msg = &data->msi_entry;
struct IO_APIC_route_entry *entry;
struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
if (!iommu)
@ -3671,31 +3642,16 @@ static void irq_remapping_prepare_irte(struct amd_ir_data *data,
data->irq_2_irte.devid = devid;
data->irq_2_irte.index = index + sub_handle;
iommu->irte_ops->prepare(data->entry, apic->irq_delivery_mode,
apic->irq_dest_mode, irq_cfg->vector,
iommu->irte_ops->prepare(data->entry, apic->delivery_mode,
apic->dest_mode_logical, irq_cfg->vector,
irq_cfg->dest_apicid, devid);
switch (info->type) {
case X86_IRQ_ALLOC_TYPE_IOAPIC:
/* Setup IOAPIC entry */
entry = info->ioapic.entry;
info->ioapic.entry = NULL;
memset(entry, 0, sizeof(*entry));
entry->vector = index;
entry->mask = 0;
entry->trigger = info->ioapic.trigger;
entry->polarity = info->ioapic.polarity;
/* Mask level triggered irqs. */
if (info->ioapic.trigger)
entry->mask = 1;
break;
case X86_IRQ_ALLOC_TYPE_HPET:
case X86_IRQ_ALLOC_TYPE_PCI_MSI:
case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
msg->address_hi = MSI_ADDR_BASE_HI;
msg->address_lo = MSI_ADDR_BASE_LO;
msg->data = irte_info->index;
fill_msi_msg(&data->msi_entry, irte_info->index);
break;
default:
@ -3892,7 +3848,26 @@ static void irq_remapping_deactivate(struct irq_domain *domain,
irte_info->index);
}
static int irq_remapping_select(struct irq_domain *d, struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token)
{
struct amd_iommu *iommu;
int devid = -1;
if (x86_fwspec_is_ioapic(fwspec))
devid = get_ioapic_devid(fwspec->param[0]);
else if (x86_fwspec_is_hpet(fwspec))
devid = get_hpet_devid(fwspec->param[0]);
if (devid < 0)
return 0;
iommu = amd_iommu_rlookup_table[devid];
return iommu && iommu->ir_domain == d;
}
static const struct irq_domain_ops amd_ir_domain_ops = {
.select = irq_remapping_select,
.alloc = irq_remapping_alloc,
.free = irq_remapping_free,
.activate = irq_remapping_activate,
@ -3943,8 +3918,8 @@ int amd_iommu_deactivate_guest_mode(void *data)
entry->hi.val = 0;
entry->lo.fields_remap.valid = valid;
entry->lo.fields_remap.dm = apic->irq_dest_mode;
entry->lo.fields_remap.int_type = apic->irq_delivery_mode;
entry->lo.fields_remap.dm = apic->dest_mode_logical;
entry->lo.fields_remap.int_type = apic->delivery_mode;
entry->hi.fields.vector = cfg->vector;
entry->lo.fields_remap.destination =
APICID_TO_IRTE_DEST_LO(cfg->dest_apicid);

View File

@ -40,7 +40,6 @@ static int hyperv_ir_set_affinity(struct irq_data *data,
{
struct irq_data *parent = data->parent_data;
struct irq_cfg *cfg = irqd_cfg(data);
struct IO_APIC_route_entry *entry;
int ret;
/* Return error If new irq affinity is out of ioapic_max_cpumask. */
@ -51,9 +50,6 @@ static int hyperv_ir_set_affinity(struct irq_data *data,
if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
return ret;
entry = data->chip_data;
entry->dest = cfg->dest_apicid;
entry->vector = cfg->vector;
send_cleanup_vector(cfg);
return 0;
@ -89,20 +85,6 @@ static int hyperv_irq_remapping_alloc(struct irq_domain *domain,
irq_data->chip = &hyperv_ir_chip;
/*
* If there is interrupt remapping function of IOMMU, setting irq
* affinity only needs to change IRTE of IOMMU. But Hyper-V doesn't
* support interrupt remapping function, setting irq affinity of IO-APIC
* interrupts still needs to change IO-APIC registers. But ioapic_
* configure_entry() will ignore value of cfg->vector and cfg->
* dest_apicid when IO-APIC's parent irq domain is not the vector
* domain.(See ioapic_configure_entry()) In order to setting vector
* and dest_apicid to IO-APIC register, IO-APIC entry pointer is saved
* in the chip_data and hyperv_irq_remapping_activate()/hyperv_ir_set_
* affinity() set vector and dest_apicid directly into IO-APIC entry.
*/
irq_data->chip_data = info->ioapic.entry;
/*
* Hypver-V IO APIC irq affinity should be in the scope of
* ioapic_max_cpumask because no irq remapping support.
@ -119,22 +101,18 @@ static void hyperv_irq_remapping_free(struct irq_domain *domain,
irq_domain_free_irqs_common(domain, virq, nr_irqs);
}
static int hyperv_irq_remapping_activate(struct irq_domain *domain,
struct irq_data *irq_data, bool reserve)
static int hyperv_irq_remapping_select(struct irq_domain *d,
struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token)
{
struct irq_cfg *cfg = irqd_cfg(irq_data);
struct IO_APIC_route_entry *entry = irq_data->chip_data;
entry->dest = cfg->dest_apicid;
entry->vector = cfg->vector;
return 0;
/* Claim the only I/O APIC emulated by Hyper-V */
return x86_fwspec_is_ioapic(fwspec);
}
static const struct irq_domain_ops hyperv_ir_domain_ops = {
.select = hyperv_irq_remapping_select,
.alloc = hyperv_irq_remapping_alloc,
.free = hyperv_irq_remapping_free,
.activate = hyperv_irq_remapping_activate,
};
static int __init hyperv_prepare_irq_remapping(void)
@ -143,6 +121,7 @@ static int __init hyperv_prepare_irq_remapping(void)
int i;
if (!hypervisor_is_type(X86_HYPER_MS_HYPERV) ||
x86_init.hyper.msi_ext_dest_id() ||
!x2apic_supported())
return -ENODEV;
@ -182,18 +161,9 @@ static int __init hyperv_enable_irq_remapping(void)
return IRQ_REMAP_X2APIC_MODE;
}
static struct irq_domain *hyperv_get_irq_domain(struct irq_alloc_info *info)
{
if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT)
return ioapic_ir_domain;
else
return NULL;
}
struct irq_remap_ops hyperv_irq_remap_ops = {
.prepare = hyperv_prepare_irq_remapping,
.enable = hyperv_enable_irq_remapping,
.get_irq_domain = hyperv_get_irq_domain,
};
#endif

View File

@ -20,7 +20,6 @@
#include <asm/cpu.h>
#include <asm/irq_remapping.h>
#include <asm/pci-direct.h>
#include <asm/msidef.h>
#include "../irq_remapping.h"
@ -204,13 +203,13 @@ static int modify_irte(struct irq_2_iommu *irq_iommu,
return rc;
}
static struct irq_domain *map_hpet_to_ir(u8 hpet_id)
static struct intel_iommu *map_hpet_to_iommu(u8 hpet_id)
{
int i;
for (i = 0; i < MAX_HPET_TBS; i++) {
if (ir_hpet[i].id == hpet_id && ir_hpet[i].iommu)
return ir_hpet[i].iommu->ir_domain;
return ir_hpet[i].iommu;
}
return NULL;
}
@ -226,13 +225,6 @@ static struct intel_iommu *map_ioapic_to_iommu(int apic)
return NULL;
}
static struct irq_domain *map_ioapic_to_ir(int apic)
{
struct intel_iommu *iommu = map_ioapic_to_iommu(apic);
return iommu ? iommu->ir_domain : NULL;
}
static struct irq_domain *map_dev_to_ir(struct pci_dev *dev)
{
struct dmar_drhd_unit *drhd = dmar_find_matched_drhd_unit(dev);
@ -1113,7 +1105,7 @@ static void prepare_irte(struct irte *irte, int vector, unsigned int dest)
memset(irte, 0, sizeof(*irte));
irte->present = 1;
irte->dst_mode = apic->irq_dest_mode;
irte->dst_mode = apic->dest_mode_logical;
/*
* Trigger mode in the IRTE will always be edge, and for IO-APIC, the
* actual level or edge trigger will be setup in the IO-APIC
@ -1122,35 +1114,18 @@ static void prepare_irte(struct irte *irte, int vector, unsigned int dest)
* irq migration in the presence of interrupt-remapping.
*/
irte->trigger_mode = 0;
irte->dlvry_mode = apic->irq_delivery_mode;
irte->dlvry_mode = apic->delivery_mode;
irte->vector = vector;
irte->dest_id = IRTE_DEST(dest);
irte->redir_hint = 1;
}
static struct irq_domain *intel_get_irq_domain(struct irq_alloc_info *info)
{
if (!info)
return NULL;
switch (info->type) {
case X86_IRQ_ALLOC_TYPE_IOAPIC_GET_PARENT:
return map_ioapic_to_ir(info->devid);
case X86_IRQ_ALLOC_TYPE_HPET_GET_PARENT:
return map_hpet_to_ir(info->devid);
default:
WARN_ON_ONCE(1);
return NULL;
}
}
struct irq_remap_ops intel_irq_remap_ops = {
.prepare = intel_prepare_irq_remapping,
.enable = intel_enable_irq_remapping,
.disable = disable_irq_remapping,
.reenable = reenable_irq_remapping,
.enable_faulting = enable_drhd_fault_handling,
.get_irq_domain = intel_get_irq_domain,
};
static void intel_ir_reconfigure_irte(struct irq_data *irqd, bool force)
@ -1260,16 +1235,30 @@ static struct irq_chip intel_ir_chip = {
.irq_set_vcpu_affinity = intel_ir_set_vcpu_affinity,
};
static void fill_msi_msg(struct msi_msg *msg, u32 index, u32 subhandle)
{
memset(msg, 0, sizeof(*msg));
msg->arch_addr_lo.dmar_base_address = X86_MSI_BASE_ADDRESS_LOW;
msg->arch_addr_lo.dmar_subhandle_valid = true;
msg->arch_addr_lo.dmar_format = true;
msg->arch_addr_lo.dmar_index_0_14 = index & 0x7FFF;
msg->arch_addr_lo.dmar_index_15 = !!(index & 0x8000);
msg->address_hi = X86_MSI_BASE_ADDRESS_HIGH;
msg->arch_data.dmar_subhandle = subhandle;
}
static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
struct irq_cfg *irq_cfg,
struct irq_alloc_info *info,
int index, int sub_handle)
{
struct IR_IO_APIC_route_entry *entry;
struct irte *irte = &data->irte_entry;
struct msi_msg *msg = &data->msi_entry;
prepare_irte(irte, irq_cfg->vector, irq_cfg->dest_apicid);
switch (info->type) {
case X86_IRQ_ALLOC_TYPE_IOAPIC:
/* Set source-id of interrupt request */
@ -1280,46 +1269,20 @@ static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
irte->trigger_mode, irte->dlvry_mode,
irte->avail, irte->vector, irte->dest_id,
irte->sid, irte->sq, irte->svt);
entry = (struct IR_IO_APIC_route_entry *)info->ioapic.entry;
info->ioapic.entry = NULL;
memset(entry, 0, sizeof(*entry));
entry->index2 = (index >> 15) & 0x1;
entry->zero = 0;
entry->format = 1;
entry->index = (index & 0x7fff);
/*
* IO-APIC RTE will be configured with virtual vector.
* irq handler will do the explicit EOI to the io-apic.
*/
entry->vector = info->ioapic.pin;
entry->mask = 0; /* enable IRQ */
entry->trigger = info->ioapic.trigger;
entry->polarity = info->ioapic.polarity;
if (info->ioapic.trigger)
entry->mask = 1; /* Mask level triggered irqs. */
sub_handle = info->ioapic.pin;
break;
case X86_IRQ_ALLOC_TYPE_HPET:
set_hpet_sid(irte, info->devid);
break;
case X86_IRQ_ALLOC_TYPE_PCI_MSI:
case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
if (info->type == X86_IRQ_ALLOC_TYPE_HPET)
set_hpet_sid(irte, info->devid);
else
set_msi_sid(irte, msi_desc_to_pci_dev(info->desc));
msg->address_hi = MSI_ADDR_BASE_HI;
msg->data = sub_handle;
msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
MSI_ADDR_IR_SHV |
MSI_ADDR_IR_INDEX1(index) |
MSI_ADDR_IR_INDEX2(index);
set_msi_sid(irte, msi_desc_to_pci_dev(info->desc));
break;
default:
BUG_ON(1);
break;
}
fill_msi_msg(&data->msi_entry, index, sub_handle);
}
static void intel_free_irq_resources(struct irq_domain *domain,
@ -1444,7 +1407,22 @@ static void intel_irq_remapping_deactivate(struct irq_domain *domain,
modify_irte(&data->irq_2_iommu, &entry);
}
static int intel_irq_remapping_select(struct irq_domain *d,
struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token)
{
struct intel_iommu *iommu = NULL;
if (x86_fwspec_is_ioapic(fwspec))
iommu = map_ioapic_to_iommu(fwspec->param[0]);
else if (x86_fwspec_is_hpet(fwspec))
iommu = map_hpet_to_iommu(fwspec->param[0]);
return iommu && d == iommu->ir_domain;
}
static const struct irq_domain_ops intel_ir_domain_ops = {
.select = intel_irq_remapping_select,
.alloc = intel_irq_remapping_alloc,
.free = intel_irq_remapping_free,
.activate = intel_irq_remapping_activate,

View File

@ -158,17 +158,3 @@ void panic_if_irq_remap(const char *msg)
if (irq_remapping_enabled)
panic(msg);
}
/**
* irq_remapping_get_irq_domain - Get the irqdomain serving the request @info
* @info: interrupt allocation information, used to identify the IOMMU device
*
* Returns pointer to IRQ domain, or NULL on failure.
*/
struct irq_domain *irq_remapping_get_irq_domain(struct irq_alloc_info *info)
{
if (!remap_ops || !remap_ops->get_irq_domain)
return NULL;
return remap_ops->get_irq_domain(info);
}

View File

@ -42,9 +42,6 @@ struct irq_remap_ops {
/* Enable fault handling */
int (*enable_faulting)(void);
/* Get the irqdomain associated to IOMMU device */
struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *);
};
extern struct irq_remap_ops intel_irq_remap_ops;

View File

@ -1226,7 +1226,7 @@ static void hv_irq_unmask(struct irq_data *data)
params->int_target.vector = cfg->vector;
/*
* Honoring apic->irq_delivery_mode set to dest_Fixed by
* Honoring apic->delivery_mode set to APIC_DELIVERY_MODE_FIXED by
* setting the HV_DEVICE_INTERRUPT_TARGET_MULTICAST flag results in a
* spurious interrupt storm. Not doing so does not seem to have a
* negative effect (yet?).
@ -1324,7 +1324,7 @@ static u32 hv_compose_msi_req_v1(
int_pkt->wslot.slot = slot;
int_pkt->int_desc.vector = vector;
int_pkt->int_desc.vector_count = 1;
int_pkt->int_desc.delivery_mode = dest_Fixed;
int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED;
/*
* Create MSI w/ dummy vCPU set, overwritten by subsequent retarget in
@ -1345,7 +1345,7 @@ static u32 hv_compose_msi_req_v2(
int_pkt->wslot.slot = slot;
int_pkt->int_desc.vector = vector;
int_pkt->int_desc.vector_count = 1;
int_pkt->int_desc.delivery_mode = dest_Fixed;
int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED;
/*
* Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten

View File

@ -18,7 +18,6 @@
#include <asm/irqdomain.h>
#include <asm/device.h>
#include <asm/msi.h>
#include <asm/msidef.h>
#define VMD_CFGBAR 0
#define VMD_MEMBAR1 2
@ -131,10 +130,10 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
struct vmd_irq_list *irq = vmdirq->irq;
struct vmd_dev *vmd = irq_data_get_irq_handler_data(data);
msg->address_hi = MSI_ADDR_BASE_HI;
msg->address_lo = MSI_ADDR_BASE_LO |
MSI_ADDR_DEST_ID(index_from_irqs(vmd, irq));
msg->data = 0;
memset(msg, 0, sizeof(*msg));
msg->address_hi = X86_MSI_BASE_ADDRESS_HIGH;
msg->arch_addr_lo.base_address = X86_MSI_BASE_ADDRESS_LOW;
msg->arch_addr_lo.destid_0_7 = index_from_irqs(vmd, irq);
}
/*

View File

@ -4,6 +4,8 @@
#include <linux/types.h>
#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
#ifndef NUM_MSI_ALLOC_SCRATCHPAD_REGS
# define NUM_MSI_ALLOC_SCRATCHPAD_REGS 2
#endif
@ -30,4 +32,6 @@ typedef struct msi_alloc_info {
#define GENERIC_MSI_DOMAIN_OPS 1
#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
#endif

View File

@ -4,11 +4,50 @@
#include <linux/kobject.h>
#include <linux/list.h>
#include <asm/msi.h>
/* Dummy shadow structures if an architecture does not define them */
#ifndef arch_msi_msg_addr_lo
typedef struct arch_msi_msg_addr_lo {
u32 address_lo;
} __attribute__ ((packed)) arch_msi_msg_addr_lo_t;
#endif
#ifndef arch_msi_msg_addr_hi
typedef struct arch_msi_msg_addr_hi {
u32 address_hi;
} __attribute__ ((packed)) arch_msi_msg_addr_hi_t;
#endif
#ifndef arch_msi_msg_data
typedef struct arch_msi_msg_data {
u32 data;
} __attribute__ ((packed)) arch_msi_msg_data_t;
#endif
/**
* msi_msg - Representation of a MSI message
* @address_lo: Low 32 bits of msi message address
* @arch_addrlo: Architecture specific shadow of @address_lo
* @address_hi: High 32 bits of msi message address
* (only used when device supports it)
* @arch_addrhi: Architecture specific shadow of @address_hi
* @data: MSI message data (usually 16 bits)
* @arch_data: Architecture specific shadow of @data
*/
struct msi_msg {
u32 address_lo; /* low 32 bits of msi message address */
u32 address_hi; /* high 32 bits of msi message address */
u32 data; /* 16 bits of msi message data */
union {
u32 address_lo;
arch_msi_msg_addr_lo_t arch_addr_lo;
};
union {
u32 address_hi;
arch_msi_msg_addr_hi_t arch_addr_hi;
};
union {
u32 data;
arch_msi_msg_data_t arch_data;
};
};
extern int pci_msi_ignore_mask;
@ -243,7 +282,6 @@ struct msi_controller {
#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
#include <linux/irqhandler.h>
#include <asm/msi.h>
struct irq_domain;
struct irq_domain_ops;

View File

@ -42,7 +42,16 @@ static inline void debugfs_add_domain_dir(struct irq_domain *d) { }
static inline void debugfs_remove_domain_dir(struct irq_domain *d) { }
#endif
const struct fwnode_operations irqchip_fwnode_ops;
static const char *irqchip_fwnode_get_name(const struct fwnode_handle *fwnode)
{
struct irqchip_fwid *fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
return fwid->name;
}
const struct fwnode_operations irqchip_fwnode_ops = {
.get_name = irqchip_fwnode_get_name,
};
EXPORT_SYMBOL_GPL(irqchip_fwnode_ops);
/**