drivers/interrupt_controller: Add a timeout check on VT-D QI operation

QI operation are not supposed to last forever.
It's not an actual timeout based on clock, but a dummy counter instead.
That's because system clock might not have beed initialized yet, since
VT-D's init comes first (and that same init will use QI...)

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
diff --git a/drivers/interrupt_controller/intc_intel_vtd.c b/drivers/interrupt_controller/intc_intel_vtd.c
index 76f478d..91a457e 100644
--- a/drivers/interrupt_controller/intc_intel_vtd.c
+++ b/drivers/interrupt_controller/intc_intel_vtd.c
@@ -117,6 +117,7 @@
 	union qi_wait_descriptor wait_desc = { 0 };
 	struct qi_descriptor *desc;
 	uint32_t wait_status;
+	uint32_t wait_count;
 
 	desc = (struct qi_descriptor *)((uintptr_t)data->qi + data->qi_tail);
 
@@ -141,12 +142,25 @@
 
 	vtd_write_reg64(dev, VTD_IQT_REG, data->qi_tail);
 
+	wait_count = 0;
+
 	while (wait_status != QI_WAIT_STATUS_COMPLETE) {
+		/* We cannot use timeout here, this function being called
+		 * at init time, it might result that the system clock
+		 * is not initialized yet since VT-D init comes first.
+		 */
+		if (wait_count > QI_WAIT_COUNT_LIMIT) {
+			printk("QI timeout\n");
+			return -ETIME;
+		}
+
 		if (vtd_read_reg32(dev, VTD_FSTS_REG) & VTD_FSTS_IQE) {
+			printk("QI error\n");
 			return -EIO;
 		}
 
 		vtd_pause_cpu();
+		wait_count++;
 	}
 
 	return 0;
diff --git a/drivers/interrupt_controller/intc_intel_vtd.h b/drivers/interrupt_controller/intc_intel_vtd.h
index 4e4ab45..682cd55 100644
--- a/drivers/interrupt_controller/intc_intel_vtd.h
+++ b/drivers/interrupt_controller/intc_intel_vtd.h
@@ -98,6 +98,9 @@
 #define QI_WAIT_STATUS_INCOMPLETE 0x0UL
 #define QI_WAIT_STATUS_COMPLETE 0x1UL
 
+/* Arbitrary wait counter limit */
+#define QI_WAIT_COUNT_LIMIT 100
+
 struct vtd_ictl_data {
 	union vtd_irte irte[IRTE_NUM] __aligned(0x1000);
 	struct qi_descriptor qi[QI_NUM] __aligned(0x1000);