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>
diff --git a/drivers/interrupt_controller/intc_ioapic.c b/drivers/interrupt_controller/intc_ioapic.c
index 4e792aa..8d5c59d 100644
--- a/drivers/interrupt_controller/intc_ioapic.c
+++ b/drivers/interrupt_controller/intc_ioapic.c
@@ -116,6 +116,31 @@
static void IoApicRedUpdateLo(unsigned int irq, uint32_t value,
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
* interrupt controller driver due to the IRQ virtualization imposed by
@@ -346,12 +371,49 @@
void z_ioapic_irq_set(unsigned int irq, unsigned int vector, uint32_t flags)
{
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 */
- rteValue = IOAPIC_INT_MASK | IOAPIC_LOGICAL |
- (vector & IOAPIC_VEC_MASK) | flags;
- ioApicRedSetHi(irq, DEFAULT_RTE_DEST);
- ioApicRedSetLo(irq, rteValue);
+ 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 |
+ (vector & IOAPIC_VEC_MASK) | flags;
+ ioApicRedSetHi(irq, DEFAULT_RTE_DEST);
+ ioApicRedSetLo(irq, rteValue);
+ }
}
/**
diff --git a/drivers/interrupt_controller/intc_ioapic_priv.h b/drivers/interrupt_controller/intc_ioapic_priv.h
index e675ea6..119f5c0 100644
--- a/drivers/interrupt_controller/intc_ioapic_priv.h
+++ b/drivers/interrupt_controller/intc_ioapic_priv.h
@@ -45,4 +45,13 @@
#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_ */
diff --git a/include/drivers/interrupt_controller/ioapic.h b/include/drivers/interrupt_controller/ioapic.h
index 154934e..2891137 100644
--- a/include/drivers/interrupt_controller/ioapic.h
+++ b/include/drivers/interrupt_controller/ioapic.h
@@ -23,6 +23,7 @@
#define IOAPIC_LEVEL 0x00008000
#define IOAPIC_EDGE 0x00000000
#define IOAPIC_REMOTE 0x00004000
+#define IOAPIC_POLARITY_MASK 0x00002000
#define IOAPIC_LOW 0x00002000
#define IOAPIC_HIGH 0x00000000
#define IOAPIC_LOGICAL 0x00000800