Skip to content

Commit 9fb1b36

Browse files
paulusmackozbenh
authored andcommitted
powerpc: Make sure IPI handlers see data written by IPI senders
We have been observing hangs, both of KVM guest vcpu tasks and more generally, where a process that is woken doesn't properly wake up and continue to run, but instead sticks in TASK_WAKING state. This happens because the update of rq->wake_list in ttwu_queue_remote() is not ordered with the update of ipi_message in smp_muxed_ipi_message_pass(), and the reading of rq->wake_list in scheduler_ipi() is not ordered with the reading of ipi_message in smp_ipi_demux(). Thus it is possible for the IPI receiver not to see the updated rq->wake_list and therefore conclude that there is nothing for it to do. In order to make sure that anything done before smp_send_reschedule() is ordered before anything done in the resulting call to scheduler_ipi(), this adds barriers in smp_muxed_message_pass() and smp_ipi_demux(). The barrier in smp_muxed_message_pass() is a full barrier to ensure that there is a full ordering between the smp_send_reschedule() caller and scheduler_ipi(). In smp_ipi_demux(), we use xchg() rather than xchg_local() because xchg() includes release and acquire barriers. Using xchg() rather than xchg_local() makes sense given that ipi_message is not just accessed locally. This moves the barrier between setting the message and calling the cause_ipi() function into the individual cause_ipi implementations. Most of them -- those that used outb, out_8 or similar -- already had a full barrier because out_8 etc. include a sync before the MMIO store. This adds an explicit barrier in the two remaining cases. These changes made no measurable difference to the speed of IPIs as measured using a simple ping-pong latency test across two CPUs on different cores of a POWER7 machine. The analysis of the reason why processes were not waking up properly is due to Milton Miller. Cc: [email protected] # v3.0+ Reported-by: Milton Miller <[email protected]> Signed-off-by: Paul Mackerras <[email protected]> Signed-off-by: Benjamin Herrenschmidt <[email protected]>
1 parent 7143328 commit 9fb1b36

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

arch/powerpc/kernel/dbell.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ void doorbell_setup_this_cpu(void)
2828

2929
void doorbell_cause_ipi(int cpu, unsigned long data)
3030
{
31+
/* Order previous accesses vs. msgsnd, which is treated as a store */
32+
mb();
3133
ppc_msgsnd(PPC_DBELL, 0, data);
3234
}
3335

arch/powerpc/kernel/smp.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,15 @@ void smp_muxed_ipi_message_pass(int cpu, int msg)
198198
struct cpu_messages *info = &per_cpu(ipi_message, cpu);
199199
char *message = (char *)&info->messages;
200200

201+
/*
202+
* Order previous accesses before accesses in the IPI handler.
203+
*/
204+
smp_mb();
201205
message[msg] = 1;
202-
mb();
206+
/*
207+
* cause_ipi functions are required to include a full barrier
208+
* before doing whatever causes the IPI.
209+
*/
203210
smp_ops->cause_ipi(cpu, info->data);
204211
}
205212

@@ -211,7 +218,7 @@ irqreturn_t smp_ipi_demux(void)
211218
mb(); /* order any irq clear */
212219

213220
do {
214-
all = xchg_local(&info->messages, 0);
221+
all = xchg(&info->messages, 0);
215222

216223
#ifdef __BIG_ENDIAN
217224
if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION)))

arch/powerpc/sysdev/xics/icp-hv.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ static inline void icp_hv_set_xirr(unsigned int value)
6565
static inline void icp_hv_set_qirr(int n_cpu , u8 value)
6666
{
6767
int hw_cpu = get_hard_smp_processor_id(n_cpu);
68-
long rc = plpar_hcall_norets(H_IPI, hw_cpu, value);
68+
long rc;
69+
70+
/* Make sure all previous accesses are ordered before IPI sending */
71+
mb();
72+
rc = plpar_hcall_norets(H_IPI, hw_cpu, value);
6973
if (rc != H_SUCCESS) {
7074
pr_err("%s: bad return code qirr cpu=%d hw_cpu=%d mfrr=0x%x "
7175
"returned %ld\n", __func__, n_cpu, hw_cpu, value, rc);

0 commit comments

Comments
 (0)