On Tue, 9 Jan 2024 11:37:45 -0800 Elliot Berman <quic_eberman@xxxxxxxxxxx> > + > +static irqreturn_t gunyah_rm_tx(int irq, void *data) > +{ > + struct gunyah_rm *rm = data; > + > + complete_all(&rm->send_ready); > + > + return IRQ_HANDLED; > +} > + > +static int gunyah_rm_msgq_send(struct gunyah_rm *rm, size_t size, bool push) > + __must_hold(&rm->send_lock) > +{ > + const u64 tx_flags = push ? GUNYAH_HYPERCALL_MSGQ_TX_FLAGS_PUSH : 0; > + enum gunyah_error gunyah_error; > + void *data = &rm->send_msg[0]; > + bool ready; lockdep_assert_held(&rm->send_lock); instead of __must_hold > + > +again: > + wait_for_completion(&rm->send_ready); > + /* reinit completion before hypercall. As soon as hypercall returns, we could get the > + * ready interrupt. This might be before we have time to reinit the completion > + */ > + reinit_completion(&rm->send_ready); Given wait_for_completion(&rm->send_ready) with rm->send_lock held, complete(&rm->send_ready) works for you with the bonus of cutting this reinit off. > + gunyah_error = gunyah_hypercall_msgq_send(rm->tx_ghrsc.capid, size, > + data, tx_flags, &ready); > + > + /* Should never happen because Linux properly tracks the ready-state of the msgq */ > + if (WARN_ON(gunyah_error == GUNYAH_ERROR_MSGQUEUE_FULL)) > + goto again; > + > + if (ready) > + complete_all(&rm->send_ready); > + > + return gunyah_error_remap(gunyah_error); > +}