Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf5a71d5 authored by Li Zhong's avatar Li Zhong Committed by Paul Mackerras
Browse files

KVM: PPC: Book 3S: XICS: Fix potential issue with duplicate IRQ resends



It is possible that in the following order, one irq is resent twice:

        CPU 1                                   CPU 2

ics_check_resend()
  lock ics_lock
    see resend set
  unlock ics_lock
                                       /* change affinity of the irq */
                                       kvmppc_xics_set_xive()
                                         write_xive()
                                           lock ics_lock
                                             see resend set
                                           unlock ics_lock

                                         icp_deliver_irq() /* resend */

  icp_deliver_irq() /* resend again */

It doesn't have any user-visible effect at present, but needs to be avoided
when the following patch implementing the P/Q stuff is applied.

This patch clears the resend flag before releasing the ics lock, when we
know we will do a re-delivery after checking the flag, or setting the flag.

Signed-off-by: default avatarLi Zhong <zhong@linux.vnet.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
parent 37451bc9
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -52,6 +52,8 @@ static void ics_rm_check_resend(struct kvmppc_xics *xics,
		if (!state->resend)
		if (!state->resend)
			continue;
			continue;


		state->resend = 0;

		arch_spin_unlock(&ics->lock);
		arch_spin_unlock(&ics->lock);
		icp_rm_deliver_irq(xics, icp, state->number);
		icp_rm_deliver_irq(xics, icp, state->number);
		arch_spin_lock(&ics->lock);
		arch_spin_lock(&ics->lock);
@@ -400,6 +402,7 @@ static void icp_rm_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
		 */
		 */
		smp_mb();
		smp_mb();
		if (!icp->state.need_resend) {
		if (!icp->state.need_resend) {
			state->resend = 0;
			arch_spin_unlock(&ics->lock);
			arch_spin_unlock(&ics->lock);
			goto again;
			goto again;
		}
		}
+4 −0
Original line number Original line Diff line number Diff line
@@ -125,6 +125,8 @@ static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
		if (!state->resend)
		if (!state->resend)
			continue;
			continue;


		state->resend = 0;

		XICS_DBG("resend %#x prio %#x\n", state->number,
		XICS_DBG("resend %#x prio %#x\n", state->number,
			      state->priority);
			      state->priority);


@@ -155,6 +157,7 @@ static bool write_xive(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
	deliver = false;
	deliver = false;
	if ((state->masked_pending || state->resend) && priority != MASKED) {
	if ((state->masked_pending || state->resend) && priority != MASKED) {
		state->masked_pending = 0;
		state->masked_pending = 0;
		state->resend = 0;
		deliver = true;
		deliver = true;
	}
	}


@@ -488,6 +491,7 @@ static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
		 */
		 */
		smp_mb();
		smp_mb();
		if (!icp->state.need_resend) {
		if (!icp->state.need_resend) {
			state->resend = 0;
			arch_spin_unlock(&ics->lock);
			arch_spin_unlock(&ics->lock);
			local_irq_restore(flags);
			local_irq_restore(flags);
			goto again;
			goto again;