It seems that we don't need to take the lock before evaluating irq's resend flag. What needed is to make sure when we clear the ics's bit in the icp's resend_map, we don't miss the resend flag of the irqs that set the bit.
And seems this could be ordered through the barrier in test_and_clear_bit(), and an newly added wmb when setting irq's resend flag, and icp's resend_map. Signed-off-by: Li Zhong <zh...@linux.vnet.ibm.com> --- arch/powerpc/kvm/book3s_hv_rm_xics.c | 14 +++++++------- arch/powerpc/kvm/book3s_xics.c | 22 +++++++--------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c index c3f604e..c3fa386 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c @@ -39,14 +39,9 @@ static void ics_rm_check_resend(struct kvmppc_xics *xics, for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { struct ics_irq_state *state = &ics->irq_state[i]; - arch_spin_lock(&state->lock); - - if (!state->resend) { - arch_spin_unlock(&state->lock); + if (!state->resend) continue; - } - arch_spin_unlock(&state->lock); icp_rm_deliver_irq(xics, icp, state->number); } } @@ -374,8 +369,13 @@ static void icp_rm_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, * We failed to deliver the interrupt we need to set the * resend map bit and mark the ICS state as needing a resend */ - set_bit(ics->icsid, icp->resend_map); state->resend = 1; + /* + * Make sure when checking resend, we don't miss the resend if + * resend_map bit is seen and cleared. + */ + smp_wmb(); + set_bit(ics->icsid, icp->resend_map); /* * If the need_resend flag got cleared in the ICP some time diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index b9dbf75..420c4fc 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -110,30 +110,17 @@ static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics, { int i; - unsigned long flags; - - local_irq_save(flags); - for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { struct ics_irq_state *state = &ics->irq_state[i]; - arch_spin_lock(&state->lock); - - if (!state->resend) { - arch_spin_unlock(&state->lock); + if (!state->resend) continue; - } XICS_DBG("resend %#x prio %#x\n", state->number, state->priority); - arch_spin_unlock(&state->lock); - local_irq_restore(flags); icp_deliver_irq(xics, icp, state->number); - local_irq_save(flags); } - - local_irq_restore(flags); } static bool write_xive(struct kvmppc_xics *xics, struct kvmppc_ics *ics, @@ -474,8 +461,13 @@ static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, * We failed to deliver the interrupt we need to set the * resend map bit and mark the ICS state as needing a resend */ - set_bit(ics->icsid, icp->resend_map); state->resend = 1; + /* + * Make sure when checking resend, we don't miss the resend if + * resend_map bit is seen and cleared. + */ + smp_wmb(); + set_bit(ics->icsid, icp->resend_map); /* * If the need_resend flag got cleared in the ICP some time -- 1.8.3.1 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev