powerpc/icswx: Fix race condition with IPI setting ACOP
There is a race where a thread causes a coprocessor type to be valid in its own ACOP _and_ in the current context, but it does not propagate to the ACOP register of other threads in time for them to use it. The original code tries to solve this by sending an IPI to all threads on the system, which is heavy handed, but unfortunately still provides a window where the icswx is issued by other threads and the ACOP is not up to date. This patch detects that the ACOP DSI fault was a "false positive" and syncs the ACOP and causes the icswx to be replayed. Signed-off-by: Jimi Xenidis <jimix@pobox.com> Cc: Anton Blanchard <anton@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
a6cf7ed511
commit
de801de139
@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(drop_cop);
|
||||
|
||||
static int acop_use_cop(int ct)
|
||||
{
|
||||
/* todo */
|
||||
/* There is no alternate policy, yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -227,11 +227,30 @@ int acop_handle_fault(struct pt_regs *regs, unsigned long address,
|
||||
ct = (ccw >> 16) & 0x3f;
|
||||
}
|
||||
|
||||
/*
|
||||
* We could be here because another thread has enabled acop
|
||||
* but the ACOP register has yet to be updated.
|
||||
*
|
||||
* This should have been taken care of by the IPI to sync all
|
||||
* the threads (see smp_call_function(sync_cop, mm, 1)), but
|
||||
* that could take forever if there are a significant amount
|
||||
* of threads.
|
||||
*
|
||||
* Given the number of threads on some of these systems,
|
||||
* perhaps this is the best way to sync ACOP rather than whack
|
||||
* every thread with an IPI.
|
||||
*/
|
||||
if ((acop_copro_type_bit(ct) & current->active_mm->context.acop) != 0) {
|
||||
sync_cop(current->active_mm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check for alternate policy */
|
||||
if (!acop_use_cop(ct))
|
||||
return 0;
|
||||
|
||||
/* at this point the CT is unknown to the system */
|
||||
pr_warn("%s[%d]: Coprocessor %d is unavailable",
|
||||
pr_warn("%s[%d]: Coprocessor %d is unavailable\n",
|
||||
current->comm, current->pid, ct);
|
||||
|
||||
/* get inst if we don't already have it */
|
||||
|
@ -59,4 +59,10 @@ extern void free_cop_pid(int free_pid);
|
||||
|
||||
extern int acop_handle_fault(struct pt_regs *regs, unsigned long address,
|
||||
unsigned long error_code);
|
||||
|
||||
static inline u64 acop_copro_type_bit(unsigned int type)
|
||||
{
|
||||
return 1ULL << (63 - type);
|
||||
}
|
||||
|
||||
#endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user