Added argument to apic_get_delivery_bitmask() for msi_redir_hint, and changed calls to the function accordingly (using 0 as a default value for non-MSI interrupts).
Modified the implementation of apic_get_delivery_bitmask() to account for the RH bit of an MSI IRQ. The RH bit indicates that the message should target only the lowest-priority processor among those specified by the logical destination of the IRQ. Signed-off-by: James Sullivan <sullivan.jame...@gmail.com> --- hw/intc/apic.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/hw/intc/apic.c b/hw/intc/apic.c index f3ec2c8..f4cc1df 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -37,7 +37,8 @@ static APICCommonState *local_apics[MAX_APICS + 1]; static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode); static void apic_update_irq(APICCommonState *s); static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, - uint8_t dest, uint8_t dest_mode); + uint8_t dest, uint8_t dest_mode, + uint8_t msi_redir_hint); static int apic_get_arb_pri(APICCommonState *s); /* Find first bit starting from msb */ @@ -326,7 +327,7 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num, trigger_mode, msi_redir_hint); - apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode, msi_redir_hint); apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode); } @@ -503,7 +504,8 @@ static int apic_find_dest(uint8_t dest) } static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, - uint8_t dest, uint8_t dest_mode) + uint8_t dest, uint8_t dest_mode, + uint8_t msi_redir_hint) { APICCommonState *apic_iter; int i; @@ -519,23 +521,27 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, } } else { /* XXX: cluster mode */ + int l = -1; memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); for(i = 0; i < MAX_APICS; i++) { apic_iter = local_apics[i]; - if (apic_iter) { - if (apic_iter->dest_mode == 0xf) { - if (dest & apic_iter->log_dest) - apic_set_bit(deliver_bitmask, i); - } else if (apic_iter->dest_mode == 0x0) { - if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) && - (dest & apic_iter->log_dest & 0x0f)) { - apic_set_bit(deliver_bitmask, i); + if (!apic_iter) { + break; + } + if (apic_match_dest(apic_iter, dest_mode, dest)) { + if (msi_redir_hint) { + if (l < 0 || + apic_compare_prio(apic_iter, local_apics[l]) < 0) { + l = i; } + } else { + apic_set_bit(deliver_bitmask, i); } - } else { - break; } } + if (msi_redir_hint && l >= 0) { + apic_set_bit(deliver_bitmask, l); + } } } @@ -568,7 +574,7 @@ static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode, switch (dest_shorthand) { case 0: - apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode, 0); break; case 1: memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); -- 2.3.4