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