summaryrefslogtreecommitdiff
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/icswx.c23
-rw-r--r--arch/powerpc/mm/icswx.h6
2 files changed, 27 insertions, 2 deletions
diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
index 5d9a59eaad9..8cdbd8634a5 100644
--- a/arch/powerpc/mm/icswx.c
+++ b/arch/powerpc/mm/icswx.c
@@ -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 */
diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
index 42176bd0884..6dedc08e62c 100644
--- a/arch/powerpc/mm/icswx.h
+++ b/arch/powerpc/mm/icswx.h
@@ -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_ */