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);