drivers/interrupt_controller: Make IOAPIC VT-D aware when relevant

If VT-D's interrupt remapping is in place, all IOAPIC RTEs need to get
remapped as well (or then they will be simply blocked).

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
Tomasz Bursztyka 2020-12-16 10:03:28 +01:00 committed by Anas Nashif
commit 2efd874dcc
3 changed files with 77 additions and 5 deletions

View file

@ -116,6 +116,31 @@ static uint32_t ioApicRedGetLo(unsigned int irq);
static void IoApicRedUpdateLo(unsigned int irq, uint32_t value, static void IoApicRedUpdateLo(unsigned int irq, uint32_t value,
uint32_t mask); uint32_t mask);
#if defined(CONFIG_INTEL_VTD_ICTL) && \
!defined(CONFIG_INTEL_VTD_ICTL_XAPIC_PASSTHROUGH)
#include <drivers/interrupt_controller/intel_vtd.h>
static const struct device *vtd;
static bool get_vtd(void)
{
if (vtd != NULL) {
return true;
}
#define DRV_COMPAT_BAK DT_DRV_COMPAT
#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT intel_vt_d
vtd = device_get_binding(DT_INST_LABEL(0));
#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT DRV_COMPAT_BAK
#undef DRV_COMPAT_BAK
return vtd == NULL ? false : true;
}
#endif /* CONFIG_INTEL_VTD_ICTL && !INTEL_VTD_ICTL_XAPIC_PASSTHROUGH */
/* /*
* The functions irq_enable() and irq_disable() are implemented in the * The functions irq_enable() and irq_disable() are implemented in the
* interrupt controller driver due to the IRQ virtualization imposed by * interrupt controller driver due to the IRQ virtualization imposed by
@ -346,13 +371,50 @@ __boot_func
void z_ioapic_irq_set(unsigned int irq, unsigned int vector, uint32_t flags) void z_ioapic_irq_set(unsigned int irq, unsigned int vector, uint32_t flags)
{ {
uint32_t rteValue; /* value to copy into redirection table entry */ uint32_t rteValue; /* value to copy into redirection table entry */
#if defined(CONFIG_INTEL_VTD_ICTL) && \
!defined(CONFIG_INTEL_VTD_ICTL_XAPIC_PASSTHROUGH)
int irte_idx;
/* the delivery mode is determined by the flags passed from drivers */ if (!get_vtd()) {
goto no_vtd;
}
irte_idx = vtd_get_irte_by_vector(vtd, vector);
if (irte_idx < 0) {
irte_idx = vtd_get_irte_by_irq(vtd, irq);
}
if (irte_idx >= 0 && !vtd_irte_is_msi(vtd, irte_idx)) {
/* Enable interrupt remapping format and set the irte index */
rteValue = IOAPIC_VTD_REMAP_FORMAT |
IOAPIC_VTD_INDEX(irte_idx);
ioApicRedSetHi(irq, rteValue);
/* Remapped: delivery mode is Fixed (000) and
* destination mode is no longer present as it is replaced by
* the 15th bit of irte index, which is always 0 in our case.
*/
rteValue = IOAPIC_INT_MASK |
(vector & IOAPIC_VEC_MASK) |
(flags & IOAPIC_TRIGGER_MASK) |
(flags & IOAPIC_POLARITY_MASK);
ioApicRedSetLo(irq, rteValue);
vtd_remap(vtd, irte_idx, vector, flags);
} else {
no_vtd:
#else
{
#endif /* CONFIG_INTEL_VTD_ICTL && !CONFIG_INTEL_VTD_ICTL_XAPIC_PASSTHROUGH */
/* the delivery mode is determined by the flags
* passed from drivers
*/
rteValue = IOAPIC_INT_MASK | IOAPIC_LOGICAL | rteValue = IOAPIC_INT_MASK | IOAPIC_LOGICAL |
(vector & IOAPIC_VEC_MASK) | flags; (vector & IOAPIC_VEC_MASK) | flags;
ioApicRedSetHi(irq, DEFAULT_RTE_DEST); ioApicRedSetHi(irq, DEFAULT_RTE_DEST);
ioApicRedSetLo(irq, rteValue); ioApicRedSetLo(irq, rteValue);
} }
}
/** /**
* *

View file

@ -45,4 +45,13 @@
#define IOAPIC_VEC_MASK 0x000000ff #define IOAPIC_VEC_MASK 0x000000ff
/* VTD related macros */
#define IOAPIC_VTD_REMAP_FORMAT BIT(16)
/* We care only about the first 14 bits.
* The 15th bits is in the first 32bits of RTE but since
* we don't go up to that value, let's ignore it.
*/
#define IOAPIC_VTD_INDEX(index) (index << 17)
#endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_IOAPIC_PRIV_H_ */ #endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_IOAPIC_PRIV_H_ */

View file

@ -23,6 +23,7 @@ extern "C" {
#define IOAPIC_LEVEL 0x00008000 #define IOAPIC_LEVEL 0x00008000
#define IOAPIC_EDGE 0x00000000 #define IOAPIC_EDGE 0x00000000
#define IOAPIC_REMOTE 0x00004000 #define IOAPIC_REMOTE 0x00004000
#define IOAPIC_POLARITY_MASK 0x00002000
#define IOAPIC_LOW 0x00002000 #define IOAPIC_LOW 0x00002000
#define IOAPIC_HIGH 0x00000000 #define IOAPIC_HIGH 0x00000000
#define IOAPIC_LOGICAL 0x00000800 #define IOAPIC_LOGICAL 0x00000800