diff --git a/drivers/interrupt_controller/intc_intel_vtd.c b/drivers/interrupt_controller/intc_intel_vtd.c index 76f478de03e..91a457e8ed7 100644 --- a/drivers/interrupt_controller/intc_intel_vtd.c +++ b/drivers/interrupt_controller/intc_intel_vtd.c @@ -117,6 +117,7 @@ static int vtd_qi_send(const struct device *dev, 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 @@ static int vtd_qi_send(const struct device *dev, 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 4e4ab45620e..682cd5562e5 100644 --- a/drivers/interrupt_controller/intc_intel_vtd.h +++ b/drivers/interrupt_controller/intc_intel_vtd.h @@ -98,6 +98,9 @@ union qi_wait_descriptor { #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);