All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing
@ 2011-09-23 15:59 Jimi Xenidis
  2011-09-23 15:59 ` [PATCH 2/3 v2] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2 Jimi Xenidis
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Jimi Xenidis @ 2011-09-23 15:59 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: anton

Some processors, like embedded, that already have a PID register that
is managed by the system.  This patch separates the ACOP and PID
processing into separate files so that the ACOP code can be shared.

Signed-off-by: Jimi Xenidis <jimix@pobox.com>

---
Re: galak@kernel.crashing.org
    Fix typo in arch/powerpc/mm/Makefile

Re: anton@samba.org
    merge in: powerpc: Fix deadlock in icswx code
---
 arch/powerpc/mm/Makefile               |    2 +
 arch/powerpc/mm/icswx.c                |  162 ++++++++++++++++++++++++++
 arch/powerpc/mm/icswx.h                |   34 ++++++
 arch/powerpc/mm/icswx_pid.c            |   87 ++++++++++++++
 arch/powerpc/mm/mmu_context_hash64.c   |  195 --------------------------------
 arch/powerpc/platforms/Kconfig.cputype |   10 ++-
 6 files changed, 294 insertions(+), 196 deletions(-)
 create mode 100644 arch/powerpc/mm/icswx.c
 create mode 100644 arch/powerpc/mm/icswx.h
 create mode 100644 arch/powerpc/mm/icswx_pid.c

diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index bdca46e..fb7976f 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -21,6 +21,8 @@ obj-$(CONFIG_PPC_STD_MMU_32)	+= ppc_mmu_32.o
 obj-$(CONFIG_PPC_STD_MMU)	+= hash_low_$(CONFIG_WORD_SIZE).o \
 				   tlb_hash$(CONFIG_WORD_SIZE).o \
 				   mmu_context_hash$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_PPC_ICSWX)		+= icswx.o
+obj-$(CONFIG_PPC_ICSWX_PID)	+= icswx_pid.o
 obj-$(CONFIG_40x)		+= 40x_mmu.o
 obj-$(CONFIG_44x)		+= 44x_mmu.o
 obj-$(CONFIG_PPC_FSL_BOOK3E)	+= fsl_booke_mmu.o
diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
new file mode 100644
index 0000000..2f1dd29
--- /dev/null
+++ b/arch/powerpc/mm/icswx.c
@@ -0,0 +1,162 @@
+/*
+ *  ICSWX and ACOP Management
+ *
+ *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include "icswx.h"
+
+
+/*
+ * The processor and its L2 cache cause the icswx instruction to
+ * generate a COP_REQ transaction on PowerBus. The transaction has no
+ * address, and the processor does not perform an MMU access to
+ * authenticate the transaction. The command portion of the PowerBus
+ * COP_REQ transaction includes the LPAR_ID (LPID) and the coprocessor
+ * Process ID (PID), which the coprocessor compares to the authorized
+ * LPID and PID held in the coprocessor, to determine if the process
+ * is authorized to generate the transaction.  The data of the COP_REQ
+ * transaction is cache block or less, typically 64 or 128 bytes in
+ * size, and is placed in cacheable memory on a 128-byte boundary
+ * _always_.
+ *
+ * The task to use a coprocessor should use use_cop() mark the use of
+ * the coprocessor type (CT) and context swithing.  On a server
+ * processor the PID register is used only for coprocessor management
+ * and so a coprocessor PID is allocated before executing icswx
+ * instruction. Drop_cop() is used to free the resources created by
+ * use_cop().
+ *
+ * Example:
+ * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
+ * Each HFI have multiple windows. Each HFI window serves as a
+ * network device sending to and receiving from HFI network.
+ * HFI immediate send function uses icswx instruction. The immediate
+ * send function allows small (single cache-line) packets be sent
+ * without using the regular HFI send FIFO and doorbell, which are
+ * much slower than immediate send.
+ *
+ * For each task intending to use HFI immediate send, the HFI driver
+ * calls use_cop() to obtain a coprocessor PID for the task.
+ * The HFI driver then allocate a free HFI window and save the
+ * coprocessor PID to the HFI window to allow the task to use the
+ * HFI window.
+ *
+ * The HFI driver repeatedly creates immediate send packets and
+ * issues icswx instruction to send data through the HFI window.
+ * The HFI compares the coprocessor PID in the CPU PID register
+ * to the PID held in the HFI window to determine if the transaction
+ * is allowed.
+ *
+ * When the task to release the HFI window, the HFI driver calls
+ * drop_cop() to release the coprocessor PID.
+ */
+
+void switch_cop(struct mm_struct *next)
+{
+#ifdef CONFIG_ICSWX_PID
+	mtspr(SPRN_PID, next->context.cop_pid);
+#endif
+	mtspr(SPRN_ACOP, next->context.acop);
+}
+
+/**
+ * Start using a coprocessor.
+ * @acop: mask of coprocessor to be used.
+ * @mm: The mm the coprocessor to associate with. Most likely current mm.
+ *
+ * Return a positive PID if successful. Negative errno otherwise.
+ * The returned PID will be fed to the coprocessor to determine if an
+ * icswx transaction is authenticated.
+ */
+int use_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int ret;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return -ENODEV;
+
+	if (!mm || !acop)
+		return -EINVAL;
+
+	/* The page_table_lock ensures mm_users won't change under us */
+	spin_lock(&mm->page_table_lock);
+	spin_lock(mm->context.cop_lockp);
+
+	ret = get_cop_pid(mm);
+	if (ret < 0)
+		goto out;
+
+	/* update acop */
+	mm->context.acop |= acop;
+
+	sync_cop(mm);
+
+	/*
+	 * If this is a threaded process then there might be other threads
+	 * running. We need to send an IPI to force them to pick up any
+	 * change in PID and ACOP.
+	 */
+	if (atomic_read(&mm->mm_users) > 1)
+		smp_call_function(sync_cop, mm, 1);
+
+out:
+	spin_unlock(mm->context.cop_lockp);
+	spin_unlock(&mm->page_table_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(use_cop);
+
+/**
+ * Stop using a coprocessor.
+ * @acop: mask of coprocessor to be stopped.
+ * @mm: The mm the coprocessor associated with.
+ */
+void drop_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int free_pid;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return;
+
+	if (WARN_ON_ONCE(!mm))
+		return;
+
+	/* The page_table_lock ensures mm_users won't change under us */
+	spin_lock(&mm->page_table_lock);
+	spin_lock(mm->context.cop_lockp);
+
+	mm->context.acop &= ~acop;
+
+	free_pid = disable_cop_pid(mm);
+	sync_cop(mm);
+
+	/*
+	 * If this is a threaded process then there might be other threads
+	 * running. We need to send an IPI to force them to pick up any
+	 * change in PID and ACOP.
+	 */
+	if (atomic_read(&mm->mm_users) > 1)
+		smp_call_function(sync_cop, mm, 1);
+
+	if (free_pid != COP_PID_NONE)
+		free_cop_pid(free_pid);
+
+	spin_unlock(mm->context.cop_lockp);
+	spin_unlock(&mm->page_table_lock);
+}
+EXPORT_SYMBOL_GPL(drop_cop);
diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
new file mode 100644
index 0000000..5121ddd
--- /dev/null
+++ b/arch/powerpc/mm/icswx.h
@@ -0,0 +1,34 @@
+/*
+ *  ICSWX and ACOP Management
+ *
+ *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <asm/mmu_context.h>
+
+/* also used to denote that PIDs are not used */
+#define COP_PID_NONE 0
+
+static inline void sync_cop(void *arg)
+{
+	struct mm_struct *mm = arg;
+
+	if (mm == current->active_mm)
+		switch_cop(current->active_mm);
+}
+
+#ifdef CONFIG_PPC_ICSWX_PID
+extern int get_cop_pid(struct mm_struct *mm);
+extern int disable_cop_pid(struct mm_struct *mm);
+extern void free_cop_pid(int free_pid);
+#else
+#define get_cop_pid(m) (COP_PID_NONE)
+#define disable_cop_pid(m) (COP_PID_NONE)
+#define free_cop_pid(p)
+#endif
diff --git a/arch/powerpc/mm/icswx_pid.c b/arch/powerpc/mm/icswx_pid.c
new file mode 100644
index 0000000..91e30eb
--- /dev/null
+++ b/arch/powerpc/mm/icswx_pid.c
@@ -0,0 +1,87 @@
+/*
+ *  ICSWX and ACOP/PID Management
+ *
+ *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include "icswx.h"
+
+#define COP_PID_MIN (COP_PID_NONE + 1)
+#define COP_PID_MAX (0xFFFF)
+
+static DEFINE_SPINLOCK(mmu_context_acop_lock);
+static DEFINE_IDA(cop_ida);
+
+static int new_cop_pid(struct ida *ida, int min_id, int max_id,
+		       spinlock_t *lock)
+{
+	int index;
+	int err;
+
+again:
+	if (!ida_pre_get(ida, GFP_KERNEL))
+		return -ENOMEM;
+
+	spin_lock(lock);
+	err = ida_get_new_above(ida, min_id, &index);
+	spin_unlock(lock);
+
+	if (err == -EAGAIN)
+		goto again;
+	else if (err)
+		return err;
+
+	if (index > max_id) {
+		spin_lock(lock);
+		ida_remove(ida, index);
+		spin_unlock(lock);
+		return -ENOMEM;
+	}
+
+	return index;
+}
+
+int get_cop_pid(struct mm_struct *mm)
+{
+	int pid;
+
+	if (mm->context.cop_pid == COP_PID_NONE) {
+		pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
+				  &mmu_context_acop_lock);
+		if (pid >= 0)
+			mm->context.cop_pid = pid;
+	}
+	return mm->context.cop_pid;
+}
+
+int disable_cop_pid(struct mm_struct *mm)
+{
+	int free_pid = COP_PID_NONE;
+
+	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
+		free_pid = mm->context.cop_pid;
+		mm->context.cop_pid = COP_PID_NONE;
+	}
+	return free_pid;
+}
+
+void free_cop_pid(int free_pid)
+{
+	spin_lock(&mmu_context_acop_lock);
+	ida_remove(&cop_ida, free_pid);
+	spin_unlock(&mmu_context_acop_lock);
+}
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index 3bafc3d..a75832c 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -24,201 +24,6 @@
 
 #include <asm/mmu_context.h>
 
-#ifdef CONFIG_PPC_ICSWX
-/*
- * The processor and its L2 cache cause the icswx instruction to
- * generate a COP_REQ transaction on PowerBus. The transaction has
- * no address, and the processor does not perform an MMU access
- * to authenticate the transaction. The command portion of the
- * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
- * the coprocessor Process ID (PID), which the coprocessor compares
- * to the authorized LPID and PID held in the coprocessor, to determine
- * if the process is authorized to generate the transaction.
- * The data of the COP_REQ transaction is 128-byte or less and is
- * placed in cacheable memory on a 128-byte cache line boundary.
- *
- * The task to use a coprocessor should use use_cop() to allocate
- * a coprocessor PID before executing icswx instruction. use_cop()
- * also enables the coprocessor context switching. Drop_cop() is
- * used to free the coprocessor PID.
- *
- * Example:
- * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
- * Each HFI have multiple windows. Each HFI window serves as a
- * network device sending to and receiving from HFI network.
- * HFI immediate send function uses icswx instruction. The immediate
- * send function allows small (single cache-line) packets be sent
- * without using the regular HFI send FIFO and doorbell, which are
- * much slower than immediate send.
- *
- * For each task intending to use HFI immediate send, the HFI driver
- * calls use_cop() to obtain a coprocessor PID for the task.
- * The HFI driver then allocate a free HFI window and save the
- * coprocessor PID to the HFI window to allow the task to use the
- * HFI window.
- *
- * The HFI driver repeatedly creates immediate send packets and
- * issues icswx instruction to send data through the HFI window.
- * The HFI compares the coprocessor PID in the CPU PID register
- * to the PID held in the HFI window to determine if the transaction
- * is allowed.
- *
- * When the task to release the HFI window, the HFI driver calls
- * drop_cop() to release the coprocessor PID.
- */
-
-#define COP_PID_NONE 0
-#define COP_PID_MIN (COP_PID_NONE + 1)
-#define COP_PID_MAX (0xFFFF)
-
-static DEFINE_SPINLOCK(mmu_context_acop_lock);
-static DEFINE_IDA(cop_ida);
-
-void switch_cop(struct mm_struct *next)
-{
-	mtspr(SPRN_PID, next->context.cop_pid);
-	mtspr(SPRN_ACOP, next->context.acop);
-}
-
-static int new_cop_pid(struct ida *ida, int min_id, int max_id,
-		       spinlock_t *lock)
-{
-	int index;
-	int err;
-
-again:
-	if (!ida_pre_get(ida, GFP_KERNEL))
-		return -ENOMEM;
-
-	spin_lock(lock);
-	err = ida_get_new_above(ida, min_id, &index);
-	spin_unlock(lock);
-
-	if (err == -EAGAIN)
-		goto again;
-	else if (err)
-		return err;
-
-	if (index > max_id) {
-		spin_lock(lock);
-		ida_remove(ida, index);
-		spin_unlock(lock);
-		return -ENOMEM;
-	}
-
-	return index;
-}
-
-static void sync_cop(void *arg)
-{
-	struct mm_struct *mm = arg;
-
-	if (mm == current->active_mm)
-		switch_cop(current->active_mm);
-}
-
-/**
- * Start using a coprocessor.
- * @acop: mask of coprocessor to be used.
- * @mm: The mm the coprocessor to associate with. Most likely current mm.
- *
- * Return a positive PID if successful. Negative errno otherwise.
- * The returned PID will be fed to the coprocessor to determine if an
- * icswx transaction is authenticated.
- */
-int use_cop(unsigned long acop, struct mm_struct *mm)
-{
-	int ret;
-
-	if (!cpu_has_feature(CPU_FTR_ICSWX))
-		return -ENODEV;
-
-	if (!mm || !acop)
-		return -EINVAL;
-
-	/* We need to make sure mm_users doesn't change */
-	down_read(&mm->mmap_sem);
-	spin_lock(mm->context.cop_lockp);
-
-	if (mm->context.cop_pid == COP_PID_NONE) {
-		ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
-				  &mmu_context_acop_lock);
-		if (ret < 0)
-			goto out;
-
-		mm->context.cop_pid = ret;
-	}
-	mm->context.acop |= acop;
-
-	sync_cop(mm);
-
-	/*
-	 * If this is a threaded process then there might be other threads
-	 * running. We need to send an IPI to force them to pick up any
-	 * change in PID and ACOP.
-	 */
-	if (atomic_read(&mm->mm_users) > 1)
-		smp_call_function(sync_cop, mm, 1);
-
-	ret = mm->context.cop_pid;
-
-out:
-	spin_unlock(mm->context.cop_lockp);
-	up_read(&mm->mmap_sem);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(use_cop);
-
-/**
- * Stop using a coprocessor.
- * @acop: mask of coprocessor to be stopped.
- * @mm: The mm the coprocessor associated with.
- */
-void drop_cop(unsigned long acop, struct mm_struct *mm)
-{
-	int free_pid = COP_PID_NONE;
-
-	if (!cpu_has_feature(CPU_FTR_ICSWX))
-		return;
-
-	if (WARN_ON_ONCE(!mm))
-		return;
-
-	/* We need to make sure mm_users doesn't change */
-	down_read(&mm->mmap_sem);
-	spin_lock(mm->context.cop_lockp);
-
-	mm->context.acop &= ~acop;
-
-	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
-		free_pid = mm->context.cop_pid;
-		mm->context.cop_pid = COP_PID_NONE;
-	}
-
-	sync_cop(mm);
-
-	/*
-	 * If this is a threaded process then there might be other threads
-	 * running. We need to send an IPI to force them to pick up any
-	 * change in PID and ACOP.
-	 */
-	if (atomic_read(&mm->mm_users) > 1)
-		smp_call_function(sync_cop, mm, 1);
-
-	if (free_pid != COP_PID_NONE) {
-		spin_lock(&mmu_context_acop_lock);
-		ida_remove(&cop_ida, free_pid);
-		spin_unlock(&mmu_context_acop_lock);
-	}
-
-	spin_unlock(mm->context.cop_lockp);
-	up_read(&mm->mmap_sem);
-}
-EXPORT_SYMBOL_GPL(drop_cop);
-
-#endif /* CONFIG_PPC_ICSWX */
-
 static DEFINE_SPINLOCK(mmu_context_lock);
 static DEFINE_IDA(mmu_context_ida);
 
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index e06e395..3cd22e5 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -234,7 +234,7 @@ config VSX
 
 config PPC_ICSWX
 	bool "Support for PowerPC icswx coprocessor instruction"
-	depends on POWER4
+	depends on POWER4 || PPC_A2
 	default n
 	---help---
 
@@ -250,6 +250,14 @@ config PPC_ICSWX
 
 	  If in doubt, say N here.
 
+config PPC_ICSWX_PID
+	bool "icswx requires direct PID management"
+	depends on PPC_ICSWX && POWER4
+	default y
+	---help---
+	  PID register in server is used explicitly for ICSWX.  In
+	  embedded systems PID managment is done by the system.
+
 config SPE
 	bool "SPE Support"
 	depends on E200 || (E500 && !PPC_E500MC)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3 v2] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2
  2011-09-23 15:59 [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing Jimi Xenidis
@ 2011-09-23 15:59 ` Jimi Xenidis
  2011-09-23 15:59 ` [PATCH 3/3 v2] powerpc: icswx: Simple ACOP fault handler for both book3e and book3s parts Jimi Xenidis
  2011-09-27 10:05 ` [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing Anton Blanchard
  2 siblings, 0 replies; 8+ messages in thread
From: Jimi Xenidis @ 2011-09-23 15:59 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: anton

ICSWX is also used by the A2 processor to access coprocessors,
although not all "chips" that contain A2s have coprocessors.

Signed-off-by: Jimi Xenidis <jimix@pobox.com>

---
Re: galak@kernel.crashing.org
    Fix white space *embarrassed*
---
 arch/powerpc/include/asm/cputable.h   |    2 +-
 arch/powerpc/include/asm/mmu-book3e.h |    4 ++++
 arch/powerpc/include/asm/reg_booke.h  |    4 ++++
 arch/powerpc/kernel/cpu_setup_a2.S    |   10 ++++++++--
 arch/powerpc/platforms/wsp/Kconfig    |    1 +
 5 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index e30442c..7044233 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -437,7 +437,7 @@ extern const char *powerpc_base_platform;
 #define CPU_FTRS_COMPATIBLE	(CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2)
 
 #define CPU_FTRS_A2 (CPU_FTR_USE_TB | CPU_FTR_SMT | CPU_FTR_DBELL | \
-		     CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN)
+		     CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN | CPU_FTR_ICSWX)
 
 #ifdef __powerpc64__
 #ifdef CONFIG_PPC_BOOK3E
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 3ea0f9a..6554608 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -212,6 +212,10 @@ typedef struct {
 	unsigned int	id;
 	unsigned int	active;
 	unsigned long	vdso_base;
+#ifdef CONFIG_PPC_ICSWX
+	struct spinlock *cop_lockp;	/* guard cop related stuff */
+	unsigned long acop;		/* mask of enabled coprocessor types */
+#endif /* CONFIG_PPC_ICSWX */
 } mm_context_t;
 
 /* Page size definitions, common between 32 and 64-bit
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 9ec0b39..e927049 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -187,6 +187,10 @@
 #define SPRN_CSRR1	SPRN_SRR3 /* Critical Save and Restore Register 1 */
 #endif
 
+#ifdef CONFIG_PPC_ICSWX
+#define SPRN_HACOP	0x15F	/* Hypervisor Available Coprocessor Register */
+#endif
+
 /* Bit definitions for CCR1. */
 #define	CCR1_DPC	0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */
 #define	CCR1_TCS	0x00000080 /* Timer Clock Select */
diff --git a/arch/powerpc/kernel/cpu_setup_a2.S b/arch/powerpc/kernel/cpu_setup_a2.S
index 7f818fe..ebc62f4 100644
--- a/arch/powerpc/kernel/cpu_setup_a2.S
+++ b/arch/powerpc/kernel/cpu_setup_a2.S
@@ -41,11 +41,16 @@ _GLOBAL(__setup_cpu_a2)
 	 * core local but doing it always won't hurt
 	 */
 
-#ifdef CONFIG_PPC_WSP_COPRO
+#ifdef CONFIG_PPC_ICSWX
 	/* Make sure ACOP starts out as zero */
 	li	r3,0
 	mtspr   SPRN_ACOP,r3
 
+	/* Skip the following if we are in Guest mode */
+	mfmsr	r3
+	andis.	r0,r3,MSR_GS@h
+	bne	_icswx_skip_guest
+
 	/* Enable icswx instruction */
 	mfspr   r3,SPRN_A2_CCR2
 	ori     r3,r3,A2_CCR2_ENABLE_ICSWX
@@ -54,7 +59,8 @@ _GLOBAL(__setup_cpu_a2)
 	/* Unmask all CTs in HACOP */
 	li      r3,-1
 	mtspr   SPRN_HACOP,r3
-#endif /* CONFIG_PPC_WSP_COPRO */
+_icswx_skip_guest:
+#endif /* CONFIG_PPC_ICSWX */
 
 	/* Enable doorbell */
 	mfspr   r3,SPRN_A2_CCR2
diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig
index d051581..3540293 100644
--- a/arch/powerpc/platforms/wsp/Kconfig
+++ b/arch/powerpc/platforms/wsp/Kconfig
@@ -1,6 +1,7 @@
 config PPC_WSP
 	bool
 	select PPC_A2
+	select PPC_ICSWX
 	select PPC_SCOM
 	select PPC_XICS
 	select PPC_ICP_NATIVE
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3 v2] powerpc: icswx: Simple ACOP fault handler for both book3e and book3s parts.
  2011-09-23 15:59 [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing Jimi Xenidis
  2011-09-23 15:59 ` [PATCH 2/3 v2] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2 Jimi Xenidis
@ 2011-09-23 15:59 ` Jimi Xenidis
  2011-09-27 10:05 ` [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing Anton Blanchard
  2 siblings, 0 replies; 8+ messages in thread
From: Jimi Xenidis @ 2011-09-23 15:59 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: anton

This patch adds a fault handler that responds to illegal Coprocessor
types.  Currently all CTs are treated and illegal.  There are two ways
to report the fault back to the application.  If the application used
the record form ("icswx.") then the architected "reject" is emulated.
If the application did not used the record form ("icswx") then it is
selectable by config whether the failure is silent (as architected) or
a SIGILL is generated.

In all cases pr_warn() is used to log the bad CT.

Signed-off-by: Jimi Xenidis <jimix@pobox.com>

---
Re: galak@kernel.crashing.org
 - Fix Kconfig/CONFIG mismatch
 - Removed union/bitfields and inspect the bits directly
---
 arch/powerpc/mm/fault.c                |   16 +++++
 arch/powerpc/mm/icswx.c                |  113 ++++++++++++++++++++++++++++++++
 arch/powerpc/mm/icswx.h                |   24 +++++++
 arch/powerpc/platforms/Kconfig.cputype |   13 ++++-
 4 files changed, 165 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 5efe8c9..88abe70 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -43,6 +43,7 @@
 #include <asm/tlbflush.h>
 #include <asm/siginfo.h>
 #include <mm/mmu_decl.h>
+#include <mm/icswx.h>
 
 #ifdef CONFIG_KPROBES
 static inline int notify_page_fault(struct pt_regs *regs)
@@ -143,6 +144,21 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
 	is_write = error_code & ESR_DST;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
+#ifdef CONFIG_PPC_ICSWX
+	/*
+	 * we need to do this early because this "data storage
+	 * interrupt" does not update the DAR/DEAR so we don't want to
+	 * look at it
+	 */
+	if (error_code & ICSWX_DSI_UCT) {
+		int ret;
+
+		ret = acop_handle_fault(regs, address, error_code);
+		if (ret)
+			return ret;
+	}
+#endif
+
 	if (notify_page_fault(regs))
 		return 0;
 
diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
index 2f1dd29..c8626cc 100644
--- a/arch/powerpc/mm/icswx.c
+++ b/arch/powerpc/mm/icswx.c
@@ -17,6 +17,8 @@
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
+
 #include "icswx.h"
 
 
@@ -160,3 +162,114 @@ void drop_cop(unsigned long acop, struct mm_struct *mm)
 	spin_unlock(&mm->page_table_lock);
 }
 EXPORT_SYMBOL_GPL(drop_cop);
+
+static int acop_use_cop(int ct)
+{
+	/* todo */
+	return -1;
+}
+
+/*
+ * Get the instruction word at the NIP
+ */
+static u32 acop_get_inst(struct pt_regs *regs)
+{
+	u32 inst;
+	u32 __user *p;
+
+	p = (u32 __user *)regs->nip;
+	if (!access_ok(VERIFY_READ, p, sizeof(*p)))
+		return 0;
+
+	if (__get_user(inst, p))
+		return 0;
+
+	return inst;
+}
+
+/**
+ * @regs: regsiters at time of interrupt
+ * @address: storage address
+ * @error_code: Fault code, usually the DSISR or ESR depending on
+ *		processor type
+ *
+ * Return 0 if we are able to resolve the data storage fault that
+ * results from a CT miss in the ACOP register.
+ */
+int acop_handle_fault(struct pt_regs *regs, unsigned long address,
+		      unsigned long error_code)
+{
+	int ct;
+	u32 inst = 0;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX)) {
+		pr_info("No coprocessors available");
+		_exception(SIGILL, regs, ILL_ILLOPN, address);
+	}
+
+	if (!user_mode(regs)) {
+		/* this could happen if the HV denies the
+		 * kernel access, for now we just die */
+		die("ICSWX from kernel failed", regs, SIGSEGV);
+	}
+
+	/* Some implementations leave us a hint for the CT */
+	ct = ICSWX_GET_CT_HINT(error_code);
+	if (ct < 0) {
+		/* we have to peek at the instruction word to figure out CT */
+		u32 ccw;
+		u32 rs;
+
+		inst = acop_get_inst(regs);
+		if (inst == 0)
+			return -1;
+
+		rs = (inst >> (31 - 10)) & 0x1f;
+		ccw = regs->gpr[rs];
+		ct = (ccw >> 16) & 0x3f;
+	}
+
+	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",
+		current->comm, current->pid, ct);
+
+	/* get inst if we don't already have it */
+	if (inst == 0) {
+		inst = acop_get_inst(regs);
+		if (inst == 0)
+			return -1;
+	}
+
+	/* Check if the instruction is the "record form" */
+	if (inst & 1) {
+		/*
+		 * the instruction is "record" form so we can reject
+		 * using CR0
+		 */
+		regs->ccr &= ~(0xful << 28);
+		regs->ccr |= ICSWX_RC_NOT_FOUND << 28;
+
+		/* Move on to the next instruction */
+		regs->nip += 4;
+	} else {
+		/*
+		 * There is no architected mechanism to report a bad
+		 * CT so we could either SIGILL or report nothing.
+		 * Since the non-record version should only bu used
+		 * for "hints" or "don't care" we should probably do
+		 * nothing.  However, I could see how some people
+		 * might want an SIGILL so it here if you want it.
+		 */
+#ifdef CONFIG_PPC_ICSWX_USE_SIGILL
+		_exception(SIGILL, regs, ILL_ILLOPN, address);
+#else
+		regs->nip += 4;
+#endif
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(acop_handle_fault);
diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
index 5121ddd..4c1ecc3 100644
--- a/arch/powerpc/mm/icswx.h
+++ b/arch/powerpc/mm/icswx.h
@@ -32,3 +32,27 @@ extern void free_cop_pid(int free_pid);
 #define disable_cop_pid(m) (COP_PID_NONE)
 #define free_cop_pid(p)
 #endif
+
+/*
+ * These are implementation bits for architected registers.  If this
+ * ever becomes architecture the should be moved to reg.h et. al.
+ */
+/* UCT is the same bit for Server and Embedded */
+#define ICSWX_DSI_UCT		0x00004000  /* Unavailable Coprocessor Type */
+
+#ifdef CONFIG_BOOKE
+/* Embedded implementation gives us no hits as to what the CT is */
+#define ICSWX_GET_CT_HINT(x) (-1)
+#else
+/* Server implementation contains the CT value in the DSISR */
+#define ICSWX_DSISR_CTMASK	0x00003f00
+#define ICSWX_GET_CT_HINT(x)	(((x) & ICSWX_DSISR_CTMASK) >> 8)
+#endif
+
+#define ICSWX_RC_STARTED	0x8	/* The request has been started */
+#define ICSWX_RC_NOT_IDLE	0x4	/* No coprocessor found idle */
+#define ICSWX_RC_NOT_FOUND	0x2	/* No coprocessor found */
+#define ICSWX_RC_UNDEFINED	0x1	/* Reserved */
+
+extern int acop_handle_fault(struct pt_regs *regs, unsigned long address,
+			     unsigned long error_code);
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 3cd22e5..4173129 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -255,9 +255,20 @@ config PPC_ICSWX_PID
 	depends on PPC_ICSWX && POWER4
 	default y
 	---help---
-	  PID register in server is used explicitly for ICSWX.  In
+	  The PID register in server is used explicitly for ICSWX.  In
 	  embedded systems PID managment is done by the system.
 
+config PPC_ICSWX_USE_SIGILL
+	bool "Should a bad CT cause a SIGILL?"
+	depends on PPC_ICSWX
+	default n
+	---help---
+	  Should a bad CT used for "non-record form ICSWX" cause an
+	  illegal intruction signal or should it be silent as
+	  architected.
+
+	  If in doubt, say N here.
+
 config SPE
 	bool "SPE Support"
 	depends on E200 || (E500 && !PPC_E500MC)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing
  2011-09-23 15:59 [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing Jimi Xenidis
  2011-09-23 15:59 ` [PATCH 2/3 v2] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2 Jimi Xenidis
  2011-09-23 15:59 ` [PATCH 3/3 v2] powerpc: icswx: Simple ACOP fault handler for both book3e and book3s parts Jimi Xenidis
@ 2011-09-27 10:05 ` Anton Blanchard
  2011-09-29  7:02   ` Benjamin Herrenschmidt
  2 siblings, 1 reply; 8+ messages in thread
From: Anton Blanchard @ 2011-09-27 10:05 UTC (permalink / raw)
  To: Jimi Xenidis; +Cc: linuxppc-dev


Hi Jimi,

> Some processors, like embedded, that already have a PID register that
> is managed by the system.  This patch separates the ACOP and PID
> processing into separate files so that the ACOP code can be shared.
> 
> Signed-off-by: Jimi Xenidis <jimix@pobox.com>

Looks good.

Acked-by: Anton Blanchard <anton@samba.org>

Anton

> ---
> Re: galak@kernel.crashing.org
>     Fix typo in arch/powerpc/mm/Makefile
> 
> Re: anton@samba.org
>     merge in: powerpc: Fix deadlock in icswx code
> ---
>  arch/powerpc/mm/Makefile               |    2 +
>  arch/powerpc/mm/icswx.c                |  162
> ++++++++++++++++++++++++++ arch/powerpc/mm/icswx.h                |
> 34 ++++++ arch/powerpc/mm/icswx_pid.c            |   87 ++++++++++++++
>  arch/powerpc/mm/mmu_context_hash64.c   |  195
> --------------------------------
> arch/powerpc/platforms/Kconfig.cputype |   10 ++- 6 files changed,
> 294 insertions(+), 196 deletions(-) create mode 100644
> arch/powerpc/mm/icswx.c create mode 100644 arch/powerpc/mm/icswx.h
>  create mode 100644 arch/powerpc/mm/icswx_pid.c
> 
> diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
> index bdca46e..fb7976f 100644
> --- a/arch/powerpc/mm/Makefile
> +++ b/arch/powerpc/mm/Makefile
> @@ -21,6 +21,8 @@ obj-$(CONFIG_PPC_STD_MMU_32)	+= ppc_mmu_32.o
>  obj-$(CONFIG_PPC_STD_MMU)	+= hash_low_$(CONFIG_WORD_SIZE).o \
>  				   tlb_hash$(CONFIG_WORD_SIZE).o \
>  				   mmu_context_hash$(CONFIG_WORD_SIZE).o
> +obj-$(CONFIG_PPC_ICSWX)		+= icswx.o
> +obj-$(CONFIG_PPC_ICSWX_PID)	+= icswx_pid.o
>  obj-$(CONFIG_40x)		+= 40x_mmu.o
>  obj-$(CONFIG_44x)		+= 44x_mmu.o
>  obj-$(CONFIG_PPC_FSL_BOOK3E)	+= fsl_booke_mmu.o
> diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
> new file mode 100644
> index 0000000..2f1dd29
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx.c
> @@ -0,0 +1,162 @@
> +/*
> + *  ICSWX and ACOP Management
> + *
> + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License
> + *  as published by the Free Software Foundation; either version
> + *  2 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/spinlock.h>
> +#include <linux/module.h>
> +#include "icswx.h"
> +
> +
> +/*
> + * The processor and its L2 cache cause the icswx instruction to
> + * generate a COP_REQ transaction on PowerBus. The transaction has no
> + * address, and the processor does not perform an MMU access to
> + * authenticate the transaction. The command portion of the PowerBus
> + * COP_REQ transaction includes the LPAR_ID (LPID) and the
> coprocessor
> + * Process ID (PID), which the coprocessor compares to the authorized
> + * LPID and PID held in the coprocessor, to determine if the process
> + * is authorized to generate the transaction.  The data of the
> COP_REQ
> + * transaction is cache block or less, typically 64 or 128 bytes in
> + * size, and is placed in cacheable memory on a 128-byte boundary
> + * _always_.
> + *
> + * The task to use a coprocessor should use use_cop() mark the use of
> + * the coprocessor type (CT) and context swithing.  On a server
> + * processor the PID register is used only for coprocessor management
> + * and so a coprocessor PID is allocated before executing icswx
> + * instruction. Drop_cop() is used to free the resources created by
> + * use_cop().
> + *
> + * Example:
> + * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> + * Each HFI have multiple windows. Each HFI window serves as a
> + * network device sending to and receiving from HFI network.
> + * HFI immediate send function uses icswx instruction. The immediate
> + * send function allows small (single cache-line) packets be sent
> + * without using the regular HFI send FIFO and doorbell, which are
> + * much slower than immediate send.
> + *
> + * For each task intending to use HFI immediate send, the HFI driver
> + * calls use_cop() to obtain a coprocessor PID for the task.
> + * The HFI driver then allocate a free HFI window and save the
> + * coprocessor PID to the HFI window to allow the task to use the
> + * HFI window.
> + *
> + * The HFI driver repeatedly creates immediate send packets and
> + * issues icswx instruction to send data through the HFI window.
> + * The HFI compares the coprocessor PID in the CPU PID register
> + * to the PID held in the HFI window to determine if the transaction
> + * is allowed.
> + *
> + * When the task to release the HFI window, the HFI driver calls
> + * drop_cop() to release the coprocessor PID.
> + */
> +
> +void switch_cop(struct mm_struct *next)
> +{
> +#ifdef CONFIG_ICSWX_PID
> +	mtspr(SPRN_PID, next->context.cop_pid);
> +#endif
> +	mtspr(SPRN_ACOP, next->context.acop);
> +}
> +
> +/**
> + * Start using a coprocessor.
> + * @acop: mask of coprocessor to be used.
> + * @mm: The mm the coprocessor to associate with. Most likely
> current mm.
> + *
> + * Return a positive PID if successful. Negative errno otherwise.
> + * The returned PID will be fed to the coprocessor to determine if an
> + * icswx transaction is authenticated.
> + */
> +int use_cop(unsigned long acop, struct mm_struct *mm)
> +{
> +	int ret;
> +
> +	if (!cpu_has_feature(CPU_FTR_ICSWX))
> +		return -ENODEV;
> +
> +	if (!mm || !acop)
> +		return -EINVAL;
> +
> +	/* The page_table_lock ensures mm_users won't change under
> us */
> +	spin_lock(&mm->page_table_lock);
> +	spin_lock(mm->context.cop_lockp);
> +
> +	ret = get_cop_pid(mm);
> +	if (ret < 0)
> +		goto out;
> +
> +	/* update acop */
> +	mm->context.acop |= acop;
> +
> +	sync_cop(mm);
> +
> +	/*
> +	 * If this is a threaded process then there might be other
> threads
> +	 * running. We need to send an IPI to force them to pick up
> any
> +	 * change in PID and ACOP.
> +	 */
> +	if (atomic_read(&mm->mm_users) > 1)
> +		smp_call_function(sync_cop, mm, 1);
> +
> +out:
> +	spin_unlock(mm->context.cop_lockp);
> +	spin_unlock(&mm->page_table_lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(use_cop);
> +
> +/**
> + * Stop using a coprocessor.
> + * @acop: mask of coprocessor to be stopped.
> + * @mm: The mm the coprocessor associated with.
> + */
> +void drop_cop(unsigned long acop, struct mm_struct *mm)
> +{
> +	int free_pid;
> +
> +	if (!cpu_has_feature(CPU_FTR_ICSWX))
> +		return;
> +
> +	if (WARN_ON_ONCE(!mm))
> +		return;
> +
> +	/* The page_table_lock ensures mm_users won't change under
> us */
> +	spin_lock(&mm->page_table_lock);
> +	spin_lock(mm->context.cop_lockp);
> +
> +	mm->context.acop &= ~acop;
> +
> +	free_pid = disable_cop_pid(mm);
> +	sync_cop(mm);
> +
> +	/*
> +	 * If this is a threaded process then there might be other
> threads
> +	 * running. We need to send an IPI to force them to pick up
> any
> +	 * change in PID and ACOP.
> +	 */
> +	if (atomic_read(&mm->mm_users) > 1)
> +		smp_call_function(sync_cop, mm, 1);
> +
> +	if (free_pid != COP_PID_NONE)
> +		free_cop_pid(free_pid);
> +
> +	spin_unlock(mm->context.cop_lockp);
> +	spin_unlock(&mm->page_table_lock);
> +}
> +EXPORT_SYMBOL_GPL(drop_cop);
> diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
> new file mode 100644
> index 0000000..5121ddd
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx.h
> @@ -0,0 +1,34 @@
> +/*
> + *  ICSWX and ACOP Management
> + *
> + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License
> + *  as published by the Free Software Foundation; either version
> + *  2 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <asm/mmu_context.h>
> +
> +/* also used to denote that PIDs are not used */
> +#define COP_PID_NONE 0
> +
> +static inline void sync_cop(void *arg)
> +{
> +	struct mm_struct *mm = arg;
> +
> +	if (mm == current->active_mm)
> +		switch_cop(current->active_mm);
> +}
> +
> +#ifdef CONFIG_PPC_ICSWX_PID
> +extern int get_cop_pid(struct mm_struct *mm);
> +extern int disable_cop_pid(struct mm_struct *mm);
> +extern void free_cop_pid(int free_pid);
> +#else
> +#define get_cop_pid(m) (COP_PID_NONE)
> +#define disable_cop_pid(m) (COP_PID_NONE)
> +#define free_cop_pid(p)
> +#endif
> diff --git a/arch/powerpc/mm/icswx_pid.c b/arch/powerpc/mm/icswx_pid.c
> new file mode 100644
> index 0000000..91e30eb
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx_pid.c
> @@ -0,0 +1,87 @@
> +/*
> + *  ICSWX and ACOP/PID Management
> + *
> + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License
> + *  as published by the Free Software Foundation; either version
> + *  2 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/spinlock.h>
> +#include <linux/idr.h>
> +#include <linux/module.h>
> +#include "icswx.h"
> +
> +#define COP_PID_MIN (COP_PID_NONE + 1)
> +#define COP_PID_MAX (0xFFFF)
> +
> +static DEFINE_SPINLOCK(mmu_context_acop_lock);
> +static DEFINE_IDA(cop_ida);
> +
> +static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> +		       spinlock_t *lock)
> +{
> +	int index;
> +	int err;
> +
> +again:
> +	if (!ida_pre_get(ida, GFP_KERNEL))
> +		return -ENOMEM;
> +
> +	spin_lock(lock);
> +	err = ida_get_new_above(ida, min_id, &index);
> +	spin_unlock(lock);
> +
> +	if (err == -EAGAIN)
> +		goto again;
> +	else if (err)
> +		return err;
> +
> +	if (index > max_id) {
> +		spin_lock(lock);
> +		ida_remove(ida, index);
> +		spin_unlock(lock);
> +		return -ENOMEM;
> +	}
> +
> +	return index;
> +}
> +
> +int get_cop_pid(struct mm_struct *mm)
> +{
> +	int pid;
> +
> +	if (mm->context.cop_pid == COP_PID_NONE) {
> +		pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> +				  &mmu_context_acop_lock);
> +		if (pid >= 0)
> +			mm->context.cop_pid = pid;
> +	}
> +	return mm->context.cop_pid;
> +}
> +
> +int disable_cop_pid(struct mm_struct *mm)
> +{
> +	int free_pid = COP_PID_NONE;
> +
> +	if ((!mm->context.acop) && (mm->context.cop_pid !=
> COP_PID_NONE)) {
> +		free_pid = mm->context.cop_pid;
> +		mm->context.cop_pid = COP_PID_NONE;
> +	}
> +	return free_pid;
> +}
> +
> +void free_cop_pid(int free_pid)
> +{
> +	spin_lock(&mmu_context_acop_lock);
> +	ida_remove(&cop_ida, free_pid);
> +	spin_unlock(&mmu_context_acop_lock);
> +}
> diff --git a/arch/powerpc/mm/mmu_context_hash64.c
> b/arch/powerpc/mm/mmu_context_hash64.c index 3bafc3d..a75832c 100644
> --- a/arch/powerpc/mm/mmu_context_hash64.c
> +++ b/arch/powerpc/mm/mmu_context_hash64.c
> @@ -24,201 +24,6 @@
>  
>  #include <asm/mmu_context.h>
>  
> -#ifdef CONFIG_PPC_ICSWX
> -/*
> - * The processor and its L2 cache cause the icswx instruction to
> - * generate a COP_REQ transaction on PowerBus. The transaction has
> - * no address, and the processor does not perform an MMU access
> - * to authenticate the transaction. The command portion of the
> - * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
> - * the coprocessor Process ID (PID), which the coprocessor compares
> - * to the authorized LPID and PID held in the coprocessor, to
> determine
> - * if the process is authorized to generate the transaction.
> - * The data of the COP_REQ transaction is 128-byte or less and is
> - * placed in cacheable memory on a 128-byte cache line boundary.
> - *
> - * The task to use a coprocessor should use use_cop() to allocate
> - * a coprocessor PID before executing icswx instruction. use_cop()
> - * also enables the coprocessor context switching. Drop_cop() is
> - * used to free the coprocessor PID.
> - *
> - * Example:
> - * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> - * Each HFI have multiple windows. Each HFI window serves as a
> - * network device sending to and receiving from HFI network.
> - * HFI immediate send function uses icswx instruction. The immediate
> - * send function allows small (single cache-line) packets be sent
> - * without using the regular HFI send FIFO and doorbell, which are
> - * much slower than immediate send.
> - *
> - * For each task intending to use HFI immediate send, the HFI driver
> - * calls use_cop() to obtain a coprocessor PID for the task.
> - * The HFI driver then allocate a free HFI window and save the
> - * coprocessor PID to the HFI window to allow the task to use the
> - * HFI window.
> - *
> - * The HFI driver repeatedly creates immediate send packets and
> - * issues icswx instruction to send data through the HFI window.
> - * The HFI compares the coprocessor PID in the CPU PID register
> - * to the PID held in the HFI window to determine if the transaction
> - * is allowed.
> - *
> - * When the task to release the HFI window, the HFI driver calls
> - * drop_cop() to release the coprocessor PID.
> - */
> -
> -#define COP_PID_NONE 0
> -#define COP_PID_MIN (COP_PID_NONE + 1)
> -#define COP_PID_MAX (0xFFFF)
> -
> -static DEFINE_SPINLOCK(mmu_context_acop_lock);
> -static DEFINE_IDA(cop_ida);
> -
> -void switch_cop(struct mm_struct *next)
> -{
> -	mtspr(SPRN_PID, next->context.cop_pid);
> -	mtspr(SPRN_ACOP, next->context.acop);
> -}
> -
> -static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> -		       spinlock_t *lock)
> -{
> -	int index;
> -	int err;
> -
> -again:
> -	if (!ida_pre_get(ida, GFP_KERNEL))
> -		return -ENOMEM;
> -
> -	spin_lock(lock);
> -	err = ida_get_new_above(ida, min_id, &index);
> -	spin_unlock(lock);
> -
> -	if (err == -EAGAIN)
> -		goto again;
> -	else if (err)
> -		return err;
> -
> -	if (index > max_id) {
> -		spin_lock(lock);
> -		ida_remove(ida, index);
> -		spin_unlock(lock);
> -		return -ENOMEM;
> -	}
> -
> -	return index;
> -}
> -
> -static void sync_cop(void *arg)
> -{
> -	struct mm_struct *mm = arg;
> -
> -	if (mm == current->active_mm)
> -		switch_cop(current->active_mm);
> -}
> -
> -/**
> - * Start using a coprocessor.
> - * @acop: mask of coprocessor to be used.
> - * @mm: The mm the coprocessor to associate with. Most likely
> current mm.
> - *
> - * Return a positive PID if successful. Negative errno otherwise.
> - * The returned PID will be fed to the coprocessor to determine if an
> - * icswx transaction is authenticated.
> - */
> -int use_cop(unsigned long acop, struct mm_struct *mm)
> -{
> -	int ret;
> -
> -	if (!cpu_has_feature(CPU_FTR_ICSWX))
> -		return -ENODEV;
> -
> -	if (!mm || !acop)
> -		return -EINVAL;
> -
> -	/* We need to make sure mm_users doesn't change */
> -	down_read(&mm->mmap_sem);
> -	spin_lock(mm->context.cop_lockp);
> -
> -	if (mm->context.cop_pid == COP_PID_NONE) {
> -		ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> -				  &mmu_context_acop_lock);
> -		if (ret < 0)
> -			goto out;
> -
> -		mm->context.cop_pid = ret;
> -	}
> -	mm->context.acop |= acop;
> -
> -	sync_cop(mm);
> -
> -	/*
> -	 * If this is a threaded process then there might be other
> threads
> -	 * running. We need to send an IPI to force them to pick up
> any
> -	 * change in PID and ACOP.
> -	 */
> -	if (atomic_read(&mm->mm_users) > 1)
> -		smp_call_function(sync_cop, mm, 1);
> -
> -	ret = mm->context.cop_pid;
> -
> -out:
> -	spin_unlock(mm->context.cop_lockp);
> -	up_read(&mm->mmap_sem);
> -
> -	return ret;
> -}
> -EXPORT_SYMBOL_GPL(use_cop);
> -
> -/**
> - * Stop using a coprocessor.
> - * @acop: mask of coprocessor to be stopped.
> - * @mm: The mm the coprocessor associated with.
> - */
> -void drop_cop(unsigned long acop, struct mm_struct *mm)
> -{
> -	int free_pid = COP_PID_NONE;
> -
> -	if (!cpu_has_feature(CPU_FTR_ICSWX))
> -		return;
> -
> -	if (WARN_ON_ONCE(!mm))
> -		return;
> -
> -	/* We need to make sure mm_users doesn't change */
> -	down_read(&mm->mmap_sem);
> -	spin_lock(mm->context.cop_lockp);
> -
> -	mm->context.acop &= ~acop;
> -
> -	if ((!mm->context.acop) && (mm->context.cop_pid !=
> COP_PID_NONE)) {
> -		free_pid = mm->context.cop_pid;
> -		mm->context.cop_pid = COP_PID_NONE;
> -	}
> -
> -	sync_cop(mm);
> -
> -	/*
> -	 * If this is a threaded process then there might be other
> threads
> -	 * running. We need to send an IPI to force them to pick up
> any
> -	 * change in PID and ACOP.
> -	 */
> -	if (atomic_read(&mm->mm_users) > 1)
> -		smp_call_function(sync_cop, mm, 1);
> -
> -	if (free_pid != COP_PID_NONE) {
> -		spin_lock(&mmu_context_acop_lock);
> -		ida_remove(&cop_ida, free_pid);
> -		spin_unlock(&mmu_context_acop_lock);
> -	}
> -
> -	spin_unlock(mm->context.cop_lockp);
> -	up_read(&mm->mmap_sem);
> -}
> -EXPORT_SYMBOL_GPL(drop_cop);
> -
> -#endif /* CONFIG_PPC_ICSWX */
> -
>  static DEFINE_SPINLOCK(mmu_context_lock);
>  static DEFINE_IDA(mmu_context_ida);
>  
> diff --git a/arch/powerpc/platforms/Kconfig.cputype
> b/arch/powerpc/platforms/Kconfig.cputype index e06e395..3cd22e5 100644
> --- a/arch/powerpc/platforms/Kconfig.cputype
> +++ b/arch/powerpc/platforms/Kconfig.cputype
> @@ -234,7 +234,7 @@ config VSX
>  
>  config PPC_ICSWX
>  	bool "Support for PowerPC icswx coprocessor instruction"
> -	depends on POWER4
> +	depends on POWER4 || PPC_A2
>  	default n
>  	---help---
>  
> @@ -250,6 +250,14 @@ config PPC_ICSWX
>  
>  	  If in doubt, say N here.
>  
> +config PPC_ICSWX_PID
> +	bool "icswx requires direct PID management"
> +	depends on PPC_ICSWX && POWER4
> +	default y
> +	---help---
> +	  PID register in server is used explicitly for ICSWX.  In
> +	  embedded systems PID managment is done by the system.
> +
>  config SPE
>  	bool "SPE Support"
>  	depends on E200 || (E500 && !PPC_E500MC)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing
  2011-09-27 10:05 ` [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing Anton Blanchard
@ 2011-09-29  7:02   ` Benjamin Herrenschmidt
  2011-09-29 20:55     ` [PATCH 1/3 v3] " Jimi Xenidis
                       ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Benjamin Herrenschmidt @ 2011-09-29  7:02 UTC (permalink / raw)
  To: Anton Blanchard, Jimi Xenidis; +Cc: linuxppc-dev

On Tue, 2011-09-27 at 20:05 +1000, Anton Blanchard wrote:
> Hi Jimi,
> 
> > Some processors, like embedded, that already have a PID register that
> > is managed by the system.  This patch separates the ACOP and PID
> > processing into separate files so that the ACOP code can be shared.
> > 
> > Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> 
> Looks good.
> 
> Acked-by: Anton Blanchard <anton@samba.org>

Please, update the patch so that it applies :-)

(IE. Anton's patch to fix deadlocks in the icswx code broke it, you
need to rebase and apply Anton's fix to your new copy of the code)

Cheers,
Ben.

> Anton
> 
> > ---
> > Re: galak@kernel.crashing.org
> >     Fix typo in arch/powerpc/mm/Makefile
> > 
> > Re: anton@samba.org
> >     merge in: powerpc: Fix deadlock in icswx code
> > ---
> >  arch/powerpc/mm/Makefile               |    2 +
> >  arch/powerpc/mm/icswx.c                |  162
> > ++++++++++++++++++++++++++ arch/powerpc/mm/icswx.h                |
> > 34 ++++++ arch/powerpc/mm/icswx_pid.c            |   87 ++++++++++++++
> >  arch/powerpc/mm/mmu_context_hash64.c   |  195
> > --------------------------------
> > arch/powerpc/platforms/Kconfig.cputype |   10 ++- 6 files changed,
> > 294 insertions(+), 196 deletions(-) create mode 100644
> > arch/powerpc/mm/icswx.c create mode 100644 arch/powerpc/mm/icswx.h
> >  create mode 100644 arch/powerpc/mm/icswx_pid.c
> > 
> > diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
> > index bdca46e..fb7976f 100644
> > --- a/arch/powerpc/mm/Makefile
> > +++ b/arch/powerpc/mm/Makefile
> > @@ -21,6 +21,8 @@ obj-$(CONFIG_PPC_STD_MMU_32)	+= ppc_mmu_32.o
> >  obj-$(CONFIG_PPC_STD_MMU)	+= hash_low_$(CONFIG_WORD_SIZE).o \
> >  				   tlb_hash$(CONFIG_WORD_SIZE).o \
> >  				   mmu_context_hash$(CONFIG_WORD_SIZE).o
> > +obj-$(CONFIG_PPC_ICSWX)		+= icswx.o
> > +obj-$(CONFIG_PPC_ICSWX_PID)	+= icswx_pid.o
> >  obj-$(CONFIG_40x)		+= 40x_mmu.o
> >  obj-$(CONFIG_44x)		+= 44x_mmu.o
> >  obj-$(CONFIG_PPC_FSL_BOOK3E)	+= fsl_booke_mmu.o
> > diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
> > new file mode 100644
> > index 0000000..2f1dd29
> > --- /dev/null
> > +++ b/arch/powerpc/mm/icswx.c
> > @@ -0,0 +1,162 @@
> > +/*
> > + *  ICSWX and ACOP Management
> > + *
> > + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> > + *
> > + *  This program is free software; you can redistribute it and/or
> > + *  modify it under the terms of the GNU General Public License
> > + *  as published by the Free Software Foundation; either version
> > + *  2 of the License, or (at your option) any later version.
> > + *
> > + */
> > +
> > +#include <linux/sched.h>
> > +#include <linux/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +#include <linux/mm.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/module.h>
> > +#include "icswx.h"
> > +
> > +
> > +/*
> > + * The processor and its L2 cache cause the icswx instruction to
> > + * generate a COP_REQ transaction on PowerBus. The transaction has no
> > + * address, and the processor does not perform an MMU access to
> > + * authenticate the transaction. The command portion of the PowerBus
> > + * COP_REQ transaction includes the LPAR_ID (LPID) and the
> > coprocessor
> > + * Process ID (PID), which the coprocessor compares to the authorized
> > + * LPID and PID held in the coprocessor, to determine if the process
> > + * is authorized to generate the transaction.  The data of the
> > COP_REQ
> > + * transaction is cache block or less, typically 64 or 128 bytes in
> > + * size, and is placed in cacheable memory on a 128-byte boundary
> > + * _always_.
> > + *
> > + * The task to use a coprocessor should use use_cop() mark the use of
> > + * the coprocessor type (CT) and context swithing.  On a server
> > + * processor the PID register is used only for coprocessor management
> > + * and so a coprocessor PID is allocated before executing icswx
> > + * instruction. Drop_cop() is used to free the resources created by
> > + * use_cop().
> > + *
> > + * Example:
> > + * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> > + * Each HFI have multiple windows. Each HFI window serves as a
> > + * network device sending to and receiving from HFI network.
> > + * HFI immediate send function uses icswx instruction. The immediate
> > + * send function allows small (single cache-line) packets be sent
> > + * without using the regular HFI send FIFO and doorbell, which are
> > + * much slower than immediate send.
> > + *
> > + * For each task intending to use HFI immediate send, the HFI driver
> > + * calls use_cop() to obtain a coprocessor PID for the task.
> > + * The HFI driver then allocate a free HFI window and save the
> > + * coprocessor PID to the HFI window to allow the task to use the
> > + * HFI window.
> > + *
> > + * The HFI driver repeatedly creates immediate send packets and
> > + * issues icswx instruction to send data through the HFI window.
> > + * The HFI compares the coprocessor PID in the CPU PID register
> > + * to the PID held in the HFI window to determine if the transaction
> > + * is allowed.
> > + *
> > + * When the task to release the HFI window, the HFI driver calls
> > + * drop_cop() to release the coprocessor PID.
> > + */
> > +
> > +void switch_cop(struct mm_struct *next)
> > +{
> > +#ifdef CONFIG_ICSWX_PID
> > +	mtspr(SPRN_PID, next->context.cop_pid);
> > +#endif
> > +	mtspr(SPRN_ACOP, next->context.acop);
> > +}
> > +
> > +/**
> > + * Start using a coprocessor.
> > + * @acop: mask of coprocessor to be used.
> > + * @mm: The mm the coprocessor to associate with. Most likely
> > current mm.
> > + *
> > + * Return a positive PID if successful. Negative errno otherwise.
> > + * The returned PID will be fed to the coprocessor to determine if an
> > + * icswx transaction is authenticated.
> > + */
> > +int use_cop(unsigned long acop, struct mm_struct *mm)
> > +{
> > +	int ret;
> > +
> > +	if (!cpu_has_feature(CPU_FTR_ICSWX))
> > +		return -ENODEV;
> > +
> > +	if (!mm || !acop)
> > +		return -EINVAL;
> > +
> > +	/* The page_table_lock ensures mm_users won't change under
> > us */
> > +	spin_lock(&mm->page_table_lock);
> > +	spin_lock(mm->context.cop_lockp);
> > +
> > +	ret = get_cop_pid(mm);
> > +	if (ret < 0)
> > +		goto out;
> > +
> > +	/* update acop */
> > +	mm->context.acop |= acop;
> > +
> > +	sync_cop(mm);
> > +
> > +	/*
> > +	 * If this is a threaded process then there might be other
> > threads
> > +	 * running. We need to send an IPI to force them to pick up
> > any
> > +	 * change in PID and ACOP.
> > +	 */
> > +	if (atomic_read(&mm->mm_users) > 1)
> > +		smp_call_function(sync_cop, mm, 1);
> > +
> > +out:
> > +	spin_unlock(mm->context.cop_lockp);
> > +	spin_unlock(&mm->page_table_lock);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(use_cop);
> > +
> > +/**
> > + * Stop using a coprocessor.
> > + * @acop: mask of coprocessor to be stopped.
> > + * @mm: The mm the coprocessor associated with.
> > + */
> > +void drop_cop(unsigned long acop, struct mm_struct *mm)
> > +{
> > +	int free_pid;
> > +
> > +	if (!cpu_has_feature(CPU_FTR_ICSWX))
> > +		return;
> > +
> > +	if (WARN_ON_ONCE(!mm))
> > +		return;
> > +
> > +	/* The page_table_lock ensures mm_users won't change under
> > us */
> > +	spin_lock(&mm->page_table_lock);
> > +	spin_lock(mm->context.cop_lockp);
> > +
> > +	mm->context.acop &= ~acop;
> > +
> > +	free_pid = disable_cop_pid(mm);
> > +	sync_cop(mm);
> > +
> > +	/*
> > +	 * If this is a threaded process then there might be other
> > threads
> > +	 * running. We need to send an IPI to force them to pick up
> > any
> > +	 * change in PID and ACOP.
> > +	 */
> > +	if (atomic_read(&mm->mm_users) > 1)
> > +		smp_call_function(sync_cop, mm, 1);
> > +
> > +	if (free_pid != COP_PID_NONE)
> > +		free_cop_pid(free_pid);
> > +
> > +	spin_unlock(mm->context.cop_lockp);
> > +	spin_unlock(&mm->page_table_lock);
> > +}
> > +EXPORT_SYMBOL_GPL(drop_cop);
> > diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
> > new file mode 100644
> > index 0000000..5121ddd
> > --- /dev/null
> > +++ b/arch/powerpc/mm/icswx.h
> > @@ -0,0 +1,34 @@
> > +/*
> > + *  ICSWX and ACOP Management
> > + *
> > + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> > + *
> > + *  This program is free software; you can redistribute it and/or
> > + *  modify it under the terms of the GNU General Public License
> > + *  as published by the Free Software Foundation; either version
> > + *  2 of the License, or (at your option) any later version.
> > + *
> > + */
> > +
> > +#include <asm/mmu_context.h>
> > +
> > +/* also used to denote that PIDs are not used */
> > +#define COP_PID_NONE 0
> > +
> > +static inline void sync_cop(void *arg)
> > +{
> > +	struct mm_struct *mm = arg;
> > +
> > +	if (mm == current->active_mm)
> > +		switch_cop(current->active_mm);
> > +}
> > +
> > +#ifdef CONFIG_PPC_ICSWX_PID
> > +extern int get_cop_pid(struct mm_struct *mm);
> > +extern int disable_cop_pid(struct mm_struct *mm);
> > +extern void free_cop_pid(int free_pid);
> > +#else
> > +#define get_cop_pid(m) (COP_PID_NONE)
> > +#define disable_cop_pid(m) (COP_PID_NONE)
> > +#define free_cop_pid(p)
> > +#endif
> > diff --git a/arch/powerpc/mm/icswx_pid.c b/arch/powerpc/mm/icswx_pid.c
> > new file mode 100644
> > index 0000000..91e30eb
> > --- /dev/null
> > +++ b/arch/powerpc/mm/icswx_pid.c
> > @@ -0,0 +1,87 @@
> > +/*
> > + *  ICSWX and ACOP/PID Management
> > + *
> > + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> > + *
> > + *  This program is free software; you can redistribute it and/or
> > + *  modify it under the terms of the GNU General Public License
> > + *  as published by the Free Software Foundation; either version
> > + *  2 of the License, or (at your option) any later version.
> > + *
> > + */
> > +
> > +#include <linux/sched.h>
> > +#include <linux/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +#include <linux/mm.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/idr.h>
> > +#include <linux/module.h>
> > +#include "icswx.h"
> > +
> > +#define COP_PID_MIN (COP_PID_NONE + 1)
> > +#define COP_PID_MAX (0xFFFF)
> > +
> > +static DEFINE_SPINLOCK(mmu_context_acop_lock);
> > +static DEFINE_IDA(cop_ida);
> > +
> > +static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> > +		       spinlock_t *lock)
> > +{
> > +	int index;
> > +	int err;
> > +
> > +again:
> > +	if (!ida_pre_get(ida, GFP_KERNEL))
> > +		return -ENOMEM;
> > +
> > +	spin_lock(lock);
> > +	err = ida_get_new_above(ida, min_id, &index);
> > +	spin_unlock(lock);
> > +
> > +	if (err == -EAGAIN)
> > +		goto again;
> > +	else if (err)
> > +		return err;
> > +
> > +	if (index > max_id) {
> > +		spin_lock(lock);
> > +		ida_remove(ida, index);
> > +		spin_unlock(lock);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	return index;
> > +}
> > +
> > +int get_cop_pid(struct mm_struct *mm)
> > +{
> > +	int pid;
> > +
> > +	if (mm->context.cop_pid == COP_PID_NONE) {
> > +		pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> > +				  &mmu_context_acop_lock);
> > +		if (pid >= 0)
> > +			mm->context.cop_pid = pid;
> > +	}
> > +	return mm->context.cop_pid;
> > +}
> > +
> > +int disable_cop_pid(struct mm_struct *mm)
> > +{
> > +	int free_pid = COP_PID_NONE;
> > +
> > +	if ((!mm->context.acop) && (mm->context.cop_pid !=
> > COP_PID_NONE)) {
> > +		free_pid = mm->context.cop_pid;
> > +		mm->context.cop_pid = COP_PID_NONE;
> > +	}
> > +	return free_pid;
> > +}
> > +
> > +void free_cop_pid(int free_pid)
> > +{
> > +	spin_lock(&mmu_context_acop_lock);
> > +	ida_remove(&cop_ida, free_pid);
> > +	spin_unlock(&mmu_context_acop_lock);
> > +}
> > diff --git a/arch/powerpc/mm/mmu_context_hash64.c
> > b/arch/powerpc/mm/mmu_context_hash64.c index 3bafc3d..a75832c 100644
> > --- a/arch/powerpc/mm/mmu_context_hash64.c
> > +++ b/arch/powerpc/mm/mmu_context_hash64.c
> > @@ -24,201 +24,6 @@
> >  
> >  #include <asm/mmu_context.h>
> >  
> > -#ifdef CONFIG_PPC_ICSWX
> > -/*
> > - * The processor and its L2 cache cause the icswx instruction to
> > - * generate a COP_REQ transaction on PowerBus. The transaction has
> > - * no address, and the processor does not perform an MMU access
> > - * to authenticate the transaction. The command portion of the
> > - * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
> > - * the coprocessor Process ID (PID), which the coprocessor compares
> > - * to the authorized LPID and PID held in the coprocessor, to
> > determine
> > - * if the process is authorized to generate the transaction.
> > - * The data of the COP_REQ transaction is 128-byte or less and is
> > - * placed in cacheable memory on a 128-byte cache line boundary.
> > - *
> > - * The task to use a coprocessor should use use_cop() to allocate
> > - * a coprocessor PID before executing icswx instruction. use_cop()
> > - * also enables the coprocessor context switching. Drop_cop() is
> > - * used to free the coprocessor PID.
> > - *
> > - * Example:
> > - * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> > - * Each HFI have multiple windows. Each HFI window serves as a
> > - * network device sending to and receiving from HFI network.
> > - * HFI immediate send function uses icswx instruction. The immediate
> > - * send function allows small (single cache-line) packets be sent
> > - * without using the regular HFI send FIFO and doorbell, which are
> > - * much slower than immediate send.
> > - *
> > - * For each task intending to use HFI immediate send, the HFI driver
> > - * calls use_cop() to obtain a coprocessor PID for the task.
> > - * The HFI driver then allocate a free HFI window and save the
> > - * coprocessor PID to the HFI window to allow the task to use the
> > - * HFI window.
> > - *
> > - * The HFI driver repeatedly creates immediate send packets and
> > - * issues icswx instruction to send data through the HFI window.
> > - * The HFI compares the coprocessor PID in the CPU PID register
> > - * to the PID held in the HFI window to determine if the transaction
> > - * is allowed.
> > - *
> > - * When the task to release the HFI window, the HFI driver calls
> > - * drop_cop() to release the coprocessor PID.
> > - */
> > -
> > -#define COP_PID_NONE 0
> > -#define COP_PID_MIN (COP_PID_NONE + 1)
> > -#define COP_PID_MAX (0xFFFF)
> > -
> > -static DEFINE_SPINLOCK(mmu_context_acop_lock);
> > -static DEFINE_IDA(cop_ida);
> > -
> > -void switch_cop(struct mm_struct *next)
> > -{
> > -	mtspr(SPRN_PID, next->context.cop_pid);
> > -	mtspr(SPRN_ACOP, next->context.acop);
> > -}
> > -
> > -static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> > -		       spinlock_t *lock)
> > -{
> > -	int index;
> > -	int err;
> > -
> > -again:
> > -	if (!ida_pre_get(ida, GFP_KERNEL))
> > -		return -ENOMEM;
> > -
> > -	spin_lock(lock);
> > -	err = ida_get_new_above(ida, min_id, &index);
> > -	spin_unlock(lock);
> > -
> > -	if (err == -EAGAIN)
> > -		goto again;
> > -	else if (err)
> > -		return err;
> > -
> > -	if (index > max_id) {
> > -		spin_lock(lock);
> > -		ida_remove(ida, index);
> > -		spin_unlock(lock);
> > -		return -ENOMEM;
> > -	}
> > -
> > -	return index;
> > -}
> > -
> > -static void sync_cop(void *arg)
> > -{
> > -	struct mm_struct *mm = arg;
> > -
> > -	if (mm == current->active_mm)
> > -		switch_cop(current->active_mm);
> > -}
> > -
> > -/**
> > - * Start using a coprocessor.
> > - * @acop: mask of coprocessor to be used.
> > - * @mm: The mm the coprocessor to associate with. Most likely
> > current mm.
> > - *
> > - * Return a positive PID if successful. Negative errno otherwise.
> > - * The returned PID will be fed to the coprocessor to determine if an
> > - * icswx transaction is authenticated.
> > - */
> > -int use_cop(unsigned long acop, struct mm_struct *mm)
> > -{
> > -	int ret;
> > -
> > -	if (!cpu_has_feature(CPU_FTR_ICSWX))
> > -		return -ENODEV;
> > -
> > -	if (!mm || !acop)
> > -		return -EINVAL;
> > -
> > -	/* We need to make sure mm_users doesn't change */
> > -	down_read(&mm->mmap_sem);
> > -	spin_lock(mm->context.cop_lockp);
> > -
> > -	if (mm->context.cop_pid == COP_PID_NONE) {
> > -		ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> > -				  &mmu_context_acop_lock);
> > -		if (ret < 0)
> > -			goto out;
> > -
> > -		mm->context.cop_pid = ret;
> > -	}
> > -	mm->context.acop |= acop;
> > -
> > -	sync_cop(mm);
> > -
> > -	/*
> > -	 * If this is a threaded process then there might be other
> > threads
> > -	 * running. We need to send an IPI to force them to pick up
> > any
> > -	 * change in PID and ACOP.
> > -	 */
> > -	if (atomic_read(&mm->mm_users) > 1)
> > -		smp_call_function(sync_cop, mm, 1);
> > -
> > -	ret = mm->context.cop_pid;
> > -
> > -out:
> > -	spin_unlock(mm->context.cop_lockp);
> > -	up_read(&mm->mmap_sem);
> > -
> > -	return ret;
> > -}
> > -EXPORT_SYMBOL_GPL(use_cop);
> > -
> > -/**
> > - * Stop using a coprocessor.
> > - * @acop: mask of coprocessor to be stopped.
> > - * @mm: The mm the coprocessor associated with.
> > - */
> > -void drop_cop(unsigned long acop, struct mm_struct *mm)
> > -{
> > -	int free_pid = COP_PID_NONE;
> > -
> > -	if (!cpu_has_feature(CPU_FTR_ICSWX))
> > -		return;
> > -
> > -	if (WARN_ON_ONCE(!mm))
> > -		return;
> > -
> > -	/* We need to make sure mm_users doesn't change */
> > -	down_read(&mm->mmap_sem);
> > -	spin_lock(mm->context.cop_lockp);
> > -
> > -	mm->context.acop &= ~acop;
> > -
> > -	if ((!mm->context.acop) && (mm->context.cop_pid !=
> > COP_PID_NONE)) {
> > -		free_pid = mm->context.cop_pid;
> > -		mm->context.cop_pid = COP_PID_NONE;
> > -	}
> > -
> > -	sync_cop(mm);
> > -
> > -	/*
> > -	 * If this is a threaded process then there might be other
> > threads
> > -	 * running. We need to send an IPI to force them to pick up
> > any
> > -	 * change in PID and ACOP.
> > -	 */
> > -	if (atomic_read(&mm->mm_users) > 1)
> > -		smp_call_function(sync_cop, mm, 1);
> > -
> > -	if (free_pid != COP_PID_NONE) {
> > -		spin_lock(&mmu_context_acop_lock);
> > -		ida_remove(&cop_ida, free_pid);
> > -		spin_unlock(&mmu_context_acop_lock);
> > -	}
> > -
> > -	spin_unlock(mm->context.cop_lockp);
> > -	up_read(&mm->mmap_sem);
> > -}
> > -EXPORT_SYMBOL_GPL(drop_cop);
> > -
> > -#endif /* CONFIG_PPC_ICSWX */
> > -
> >  static DEFINE_SPINLOCK(mmu_context_lock);
> >  static DEFINE_IDA(mmu_context_ida);
> >  
> > diff --git a/arch/powerpc/platforms/Kconfig.cputype
> > b/arch/powerpc/platforms/Kconfig.cputype index e06e395..3cd22e5 100644
> > --- a/arch/powerpc/platforms/Kconfig.cputype
> > +++ b/arch/powerpc/platforms/Kconfig.cputype
> > @@ -234,7 +234,7 @@ config VSX
> >  
> >  config PPC_ICSWX
> >  	bool "Support for PowerPC icswx coprocessor instruction"
> > -	depends on POWER4
> > +	depends on POWER4 || PPC_A2
> >  	default n
> >  	---help---
> >  
> > @@ -250,6 +250,14 @@ config PPC_ICSWX
> >  
> >  	  If in doubt, say N here.
> >  
> > +config PPC_ICSWX_PID
> > +	bool "icswx requires direct PID management"
> > +	depends on PPC_ICSWX && POWER4
> > +	default y
> > +	---help---
> > +	  PID register in server is used explicitly for ICSWX.  In
> > +	  embedded systems PID managment is done by the system.
> > +
> >  config SPE
> >  	bool "SPE Support"
> >  	depends on E200 || (E500 && !PPC_E500MC)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3 v3] powerpc: Split ICSWX ACOP and PID processing
  2011-09-29  7:02   ` Benjamin Herrenschmidt
@ 2011-09-29 20:55     ` Jimi Xenidis
  2011-09-29 20:55     ` [PATCH 2/3 v3] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2 Jimi Xenidis
  2011-09-29 20:55     ` [PATCH 3/3 v3] powerpc: icswx: Simple ACOP fault handler for both book3e and book3s parts Jimi Xenidis
  2 siblings, 0 replies; 8+ messages in thread
From: Jimi Xenidis @ 2011-09-29 20:55 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anton Blanchard

Some processors, like embedded, that already have a PID register that
is managed by the system.  This patch separates the ACOP and PID
processing into separate files so that the ACOP code can be shared.

Signed-off-by: Jimi Xenidis <jimix@pobox.com>

---
Re: benh@kernel.crashing.org
    rebase

--in-reply-to=1317279773.29415.181.camel@pasglop
---
 arch/powerpc/mm/Makefile               |    2 +
 arch/powerpc/mm/icswx.c                |  160 ++++++++++++++++++++++++++
 arch/powerpc/mm/icswx.h                |   39 +++++++
 arch/powerpc/mm/icswx_pid.c            |   87 ++++++++++++++
 arch/powerpc/mm/mmu_context_hash64.c   |  195 +-------------------------------
 arch/powerpc/platforms/Kconfig.cputype |    8 ++
 6 files changed, 297 insertions(+), 194 deletions(-)
 create mode 100644 arch/powerpc/mm/icswx.c
 create mode 100644 arch/powerpc/mm/icswx.h
 create mode 100644 arch/powerpc/mm/icswx_pid.c

diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 991ee81..3787b61 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -21,6 +21,8 @@ obj-$(CONFIG_PPC_STD_MMU_32)	+= ppc_mmu_32.o
 obj-$(CONFIG_PPC_STD_MMU)	+= hash_low_$(CONFIG_WORD_SIZE).o \
 				   tlb_hash$(CONFIG_WORD_SIZE).o \
 				   mmu_context_hash$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_PPC_ICSWX)		+= icswx.o
+obj-$(CONFIG_PPC_ICSWX_PID)	+= icswx_pid.o
 obj-$(CONFIG_40x)		+= 40x_mmu.o
 obj-$(CONFIG_44x)		+= 44x_mmu.o
 obj-$(CONFIG_PPC_FSL_BOOK3E)	+= fsl_booke_mmu.o
diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
new file mode 100644
index 0000000..a98850f
--- /dev/null
+++ b/arch/powerpc/mm/icswx.c
@@ -0,0 +1,160 @@
+/*
+ *  ICSWX and ACOP Management
+ *
+ *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include "icswx.h"
+
+/*
+ * The processor and its L2 cache cause the icswx instruction to
+ * generate a COP_REQ transaction on PowerBus. The transaction has no
+ * address, and the processor does not perform an MMU access to
+ * authenticate the transaction. The command portion of the PowerBus
+ * COP_REQ transaction includes the LPAR_ID (LPID) and the coprocessor
+ * Process ID (PID), which the coprocessor compares to the authorized
+ * LPID and PID held in the coprocessor, to determine if the process
+ * is authorized to generate the transaction.  The data of the COP_REQ
+ * transaction is 128-byte or less in size and is placed in cacheable
+ * memory on a 128-byte cache line boundary.
+ *
+ * The task to use a coprocessor should use use_cop() to mark the use
+ * of the Coprocessor Type (CT) and context switching. On a server
+ * class processor, the PID register is used only for coprocessor
+ * management + * and so a coprocessor PID is allocated before
+ * executing icswx + * instruction. Drop_cop() is used to free the
+ * coprocessor PID.
+ *
+ * Example:
+ * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
+ * Each HFI have multiple windows. Each HFI window serves as a
+ * network device sending to and receiving from HFI network.
+ * HFI immediate send function uses icswx instruction. The immediate
+ * send function allows small (single cache-line) packets be sent
+ * without using the regular HFI send FIFO and doorbell, which are
+ * much slower than immediate send.
+ *
+ * For each task intending to use HFI immediate send, the HFI driver
+ * calls use_cop() to obtain a coprocessor PID for the task.
+ * The HFI driver then allocate a free HFI window and save the
+ * coprocessor PID to the HFI window to allow the task to use the
+ * HFI window.
+ *
+ * The HFI driver repeatedly creates immediate send packets and
+ * issues icswx instruction to send data through the HFI window.
+ * The HFI compares the coprocessor PID in the CPU PID register
+ * to the PID held in the HFI window to determine if the transaction
+ * is allowed.
+ *
+ * When the task to release the HFI window, the HFI driver calls
+ * drop_cop() to release the coprocessor PID.
+ */
+
+void switch_cop(struct mm_struct *next)
+{
+#ifdef CONFIG_ICSWX_PID
+	mtspr(SPRN_PID, next->context.cop_pid);
+#endif
+	mtspr(SPRN_ACOP, next->context.acop);
+}
+
+/**
+ * Start using a coprocessor.
+ * @acop: mask of coprocessor to be used.
+ * @mm: The mm the coprocessor to associate with. Most likely current mm.
+ *
+ * Return a positive PID if successful. Negative errno otherwise.
+ * The returned PID will be fed to the coprocessor to determine if an
+ * icswx transaction is authenticated.
+ */
+int use_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int ret;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return -ENODEV;
+
+	if (!mm || !acop)
+		return -EINVAL;
+
+	/* The page_table_lock ensures mm_users won't change under us */
+	spin_lock(&mm->page_table_lock);
+	spin_lock(mm->context.cop_lockp);
+
+	ret = get_cop_pid(mm);
+	if (ret < 0)
+		goto out;
+
+	/* update acop */
+	mm->context.acop |= acop;
+
+	sync_cop(mm);
+
+	/*
+	 * If this is a threaded process then there might be other threads
+	 * running. We need to send an IPI to force them to pick up any
+	 * change in PID and ACOP.
+	 */
+	if (atomic_read(&mm->mm_users) > 1)
+		smp_call_function(sync_cop, mm, 1);
+
+out:
+	spin_unlock(mm->context.cop_lockp);
+	spin_unlock(&mm->page_table_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(use_cop);
+
+/**
+ * Stop using a coprocessor.
+ * @acop: mask of coprocessor to be stopped.
+ * @mm: The mm the coprocessor associated with.
+ */
+void drop_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int free_pid;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return;
+
+	if (WARN_ON_ONCE(!mm))
+		return;
+
+	/* The page_table_lock ensures mm_users won't change under us */
+	spin_lock(&mm->page_table_lock);
+	spin_lock(mm->context.cop_lockp);
+
+	mm->context.acop &= ~acop;
+
+	free_pid = disable_cop_pid(mm);
+	sync_cop(mm);
+
+	/*
+	 * If this is a threaded process then there might be other threads
+	 * running. We need to send an IPI to force them to pick up any
+	 * change in PID and ACOP.
+	 */
+	if (atomic_read(&mm->mm_users) > 1)
+		smp_call_function(sync_cop, mm, 1);
+
+	if (free_pid != COP_PID_NONE)
+		free_cop_pid(free_pid);
+
+	spin_unlock(mm->context.cop_lockp);
+	spin_unlock(&mm->page_table_lock);
+}
+EXPORT_SYMBOL_GPL(drop_cop);
diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
new file mode 100644
index 0000000..07514e4
--- /dev/null
+++ b/arch/powerpc/mm/icswx.h
@@ -0,0 +1,39 @@
+#ifndef _ARCH_POWERPC_MM_ICSWX_H_
+#define _ARCH_POWERPC_MM_ICSWX_H_
+
+/*
+ *  ICSWX and ACOP Management
+ *
+ *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <asm/mmu_context.h>
+
+/* also used to denote that PIDs are not used */
+#define COP_PID_NONE 0
+
+static inline void sync_cop(void *arg)
+{
+	struct mm_struct *mm = arg;
+
+	if (mm == current->active_mm)
+		switch_cop(current->active_mm);
+}
+
+#ifdef CONFIG_PPC_ICSWX_PID
+extern int get_cop_pid(struct mm_struct *mm);
+extern int disable_cop_pid(struct mm_struct *mm);
+extern void free_cop_pid(int free_pid);
+#else
+#define get_cop_pid(m) (COP_PID_NONE)
+#define disable_cop_pid(m) (COP_PID_NONE)
+#define free_cop_pid(p)
+#endif
+
+#endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */
diff --git a/arch/powerpc/mm/icswx_pid.c b/arch/powerpc/mm/icswx_pid.c
new file mode 100644
index 0000000..91e30eb
--- /dev/null
+++ b/arch/powerpc/mm/icswx_pid.c
@@ -0,0 +1,87 @@
+/*
+ *  ICSWX and ACOP/PID Management
+ *
+ *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include "icswx.h"
+
+#define COP_PID_MIN (COP_PID_NONE + 1)
+#define COP_PID_MAX (0xFFFF)
+
+static DEFINE_SPINLOCK(mmu_context_acop_lock);
+static DEFINE_IDA(cop_ida);
+
+static int new_cop_pid(struct ida *ida, int min_id, int max_id,
+		       spinlock_t *lock)
+{
+	int index;
+	int err;
+
+again:
+	if (!ida_pre_get(ida, GFP_KERNEL))
+		return -ENOMEM;
+
+	spin_lock(lock);
+	err = ida_get_new_above(ida, min_id, &index);
+	spin_unlock(lock);
+
+	if (err == -EAGAIN)
+		goto again;
+	else if (err)
+		return err;
+
+	if (index > max_id) {
+		spin_lock(lock);
+		ida_remove(ida, index);
+		spin_unlock(lock);
+		return -ENOMEM;
+	}
+
+	return index;
+}
+
+int get_cop_pid(struct mm_struct *mm)
+{
+	int pid;
+
+	if (mm->context.cop_pid == COP_PID_NONE) {
+		pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
+				  &mmu_context_acop_lock);
+		if (pid >= 0)
+			mm->context.cop_pid = pid;
+	}
+	return mm->context.cop_pid;
+}
+
+int disable_cop_pid(struct mm_struct *mm)
+{
+	int free_pid = COP_PID_NONE;
+
+	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
+		free_pid = mm->context.cop_pid;
+		mm->context.cop_pid = COP_PID_NONE;
+	}
+	return free_pid;
+}
+
+void free_cop_pid(int free_pid)
+{
+	spin_lock(&mmu_context_acop_lock);
+	ida_remove(&cop_ida, free_pid);
+	spin_unlock(&mmu_context_acop_lock);
+}
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index 4ff587e..9b55c63 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -24,200 +24,7 @@
 
 #include <asm/mmu_context.h>
 
-#ifdef CONFIG_PPC_ICSWX
-/*
- * The processor and its L2 cache cause the icswx instruction to
- * generate a COP_REQ transaction on PowerBus. The transaction has
- * no address, and the processor does not perform an MMU access
- * to authenticate the transaction. The command portion of the
- * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
- * the coprocessor Process ID (PID), which the coprocessor compares
- * to the authorized LPID and PID held in the coprocessor, to determine
- * if the process is authorized to generate the transaction.
- * The data of the COP_REQ transaction is 128-byte or less and is
- * placed in cacheable memory on a 128-byte cache line boundary.
- *
- * The task to use a coprocessor should use use_cop() to allocate
- * a coprocessor PID before executing icswx instruction. use_cop()
- * also enables the coprocessor context switching. Drop_cop() is
- * used to free the coprocessor PID.
- *
- * Example:
- * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
- * Each HFI have multiple windows. Each HFI window serves as a
- * network device sending to and receiving from HFI network.
- * HFI immediate send function uses icswx instruction. The immediate
- * send function allows small (single cache-line) packets be sent
- * without using the regular HFI send FIFO and doorbell, which are
- * much slower than immediate send.
- *
- * For each task intending to use HFI immediate send, the HFI driver
- * calls use_cop() to obtain a coprocessor PID for the task.
- * The HFI driver then allocate a free HFI window and save the
- * coprocessor PID to the HFI window to allow the task to use the
- * HFI window.
- *
- * The HFI driver repeatedly creates immediate send packets and
- * issues icswx instruction to send data through the HFI window.
- * The HFI compares the coprocessor PID in the CPU PID register
- * to the PID held in the HFI window to determine if the transaction
- * is allowed.
- *
- * When the task to release the HFI window, the HFI driver calls
- * drop_cop() to release the coprocessor PID.
- */
-
-#define COP_PID_NONE 0
-#define COP_PID_MIN (COP_PID_NONE + 1)
-#define COP_PID_MAX (0xFFFF)
-
-static DEFINE_SPINLOCK(mmu_context_acop_lock);
-static DEFINE_IDA(cop_ida);
-
-void switch_cop(struct mm_struct *next)
-{
-	mtspr(SPRN_PID, next->context.cop_pid);
-	mtspr(SPRN_ACOP, next->context.acop);
-}
-
-static int new_cop_pid(struct ida *ida, int min_id, int max_id,
-		       spinlock_t *lock)
-{
-	int index;
-	int err;
-
-again:
-	if (!ida_pre_get(ida, GFP_KERNEL))
-		return -ENOMEM;
-
-	spin_lock(lock);
-	err = ida_get_new_above(ida, min_id, &index);
-	spin_unlock(lock);
-
-	if (err == -EAGAIN)
-		goto again;
-	else if (err)
-		return err;
-
-	if (index > max_id) {
-		spin_lock(lock);
-		ida_remove(ida, index);
-		spin_unlock(lock);
-		return -ENOMEM;
-	}
-
-	return index;
-}
-
-static void sync_cop(void *arg)
-{
-	struct mm_struct *mm = arg;
-
-	if (mm == current->active_mm)
-		switch_cop(current->active_mm);
-}
-
-/**
- * Start using a coprocessor.
- * @acop: mask of coprocessor to be used.
- * @mm: The mm the coprocessor to associate with. Most likely current mm.
- *
- * Return a positive PID if successful. Negative errno otherwise.
- * The returned PID will be fed to the coprocessor to determine if an
- * icswx transaction is authenticated.
- */
-int use_cop(unsigned long acop, struct mm_struct *mm)
-{
-	int ret;
-
-	if (!cpu_has_feature(CPU_FTR_ICSWX))
-		return -ENODEV;
-
-	if (!mm || !acop)
-		return -EINVAL;
-
-	/* The page_table_lock ensures mm_users won't change under us */
-	spin_lock(&mm->page_table_lock);
-	spin_lock(mm->context.cop_lockp);
-
-	if (mm->context.cop_pid == COP_PID_NONE) {
-		ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
-				  &mmu_context_acop_lock);
-		if (ret < 0)
-			goto out;
-
-		mm->context.cop_pid = ret;
-	}
-	mm->context.acop |= acop;
-
-	sync_cop(mm);
-
-	/*
-	 * If this is a threaded process then there might be other threads
-	 * running. We need to send an IPI to force them to pick up any
-	 * change in PID and ACOP.
-	 */
-	if (atomic_read(&mm->mm_users) > 1)
-		smp_call_function(sync_cop, mm, 1);
-
-	ret = mm->context.cop_pid;
-
-out:
-	spin_unlock(mm->context.cop_lockp);
-	spin_unlock(&mm->page_table_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(use_cop);
-
-/**
- * Stop using a coprocessor.
- * @acop: mask of coprocessor to be stopped.
- * @mm: The mm the coprocessor associated with.
- */
-void drop_cop(unsigned long acop, struct mm_struct *mm)
-{
-	int free_pid = COP_PID_NONE;
-
-	if (!cpu_has_feature(CPU_FTR_ICSWX))
-		return;
-
-	if (WARN_ON_ONCE(!mm))
-		return;
-
-	/* The page_table_lock ensures mm_users won't change under us */
-	spin_lock(&mm->page_table_lock);
-	spin_lock(mm->context.cop_lockp);
-
-	mm->context.acop &= ~acop;
-
-	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
-		free_pid = mm->context.cop_pid;
-		mm->context.cop_pid = COP_PID_NONE;
-	}
-
-	sync_cop(mm);
-
-	/*
-	 * If this is a threaded process then there might be other threads
-	 * running. We need to send an IPI to force them to pick up any
-	 * change in PID and ACOP.
-	 */
-	if (atomic_read(&mm->mm_users) > 1)
-		smp_call_function(sync_cop, mm, 1);
-
-	if (free_pid != COP_PID_NONE) {
-		spin_lock(&mmu_context_acop_lock);
-		ida_remove(&cop_ida, free_pid);
-		spin_unlock(&mmu_context_acop_lock);
-	}
-
-	spin_unlock(mm->context.cop_lockp);
-	spin_unlock(&mm->page_table_lock);
-}
-EXPORT_SYMBOL_GPL(drop_cop);
-
-#endif /* CONFIG_PPC_ICSWX */
+#include "icswx.h"
 
 static DEFINE_SPINLOCK(mmu_context_lock);
 static DEFINE_IDA(mmu_context_ida);
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index a85990c..4868d1f 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -252,6 +252,14 @@ config PPC_ICSWX
 
 	  If in doubt, say N here.
 
+config PPC_ICSWX_PID
+	bool "icswx requires direct PID management"
+	depends on PPC_ICSWX && POWER4
+	default y
+	---help---
+	  PID register in server is used explicitly for ICSWX.  In
+	  embedded systems PID managment is done by the system.
+
 config SPE
 	bool "SPE Support"
 	depends on E200 || (E500 && !PPC_E500MC)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3 v3] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2
  2011-09-29  7:02   ` Benjamin Herrenschmidt
  2011-09-29 20:55     ` [PATCH 1/3 v3] " Jimi Xenidis
@ 2011-09-29 20:55     ` Jimi Xenidis
  2011-09-29 20:55     ` [PATCH 3/3 v3] powerpc: icswx: Simple ACOP fault handler for both book3e and book3s parts Jimi Xenidis
  2 siblings, 0 replies; 8+ messages in thread
From: Jimi Xenidis @ 2011-09-29 20:55 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anton Blanchard

ICSWX is also used by the A2 processor to access coprocessors,
although not all "chips" that contain A2s have coprocessors.

Signed-off-by: Jimi Xenidis <jimix@pobox.com>

---
Re: galak@kernel.crashing.org
    Fix white space *embarrassed*
Re: benh@kernel.crashing.org
    rebase
---
 arch/powerpc/include/asm/cputable.h    |    2 +-
 arch/powerpc/include/asm/mmu-book3e.h  |    4 ++++
 arch/powerpc/include/asm/reg_booke.h   |    4 ++++
 arch/powerpc/kernel/cpu_setup_a2.S     |   10 ++++++++--
 arch/powerpc/platforms/Kconfig.cputype |    2 +-
 arch/powerpc/platforms/wsp/Kconfig     |    1 +
 6 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index e30442c..7044233 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -437,7 +437,7 @@ extern const char *powerpc_base_platform;
 #define CPU_FTRS_COMPATIBLE	(CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2)
 
 #define CPU_FTRS_A2 (CPU_FTR_USE_TB | CPU_FTR_SMT | CPU_FTR_DBELL | \
-		     CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN)
+		     CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN | CPU_FTR_ICSWX)
 
 #ifdef __powerpc64__
 #ifdef CONFIG_PPC_BOOK3E
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 0260ea5..50210b9 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -214,6 +214,10 @@ typedef struct {
 	unsigned int	id;
 	unsigned int	active;
 	unsigned long	vdso_base;
+#ifdef CONFIG_PPC_ICSWX
+	struct spinlock *cop_lockp;	/* guard cop related stuff */
+	unsigned long acop;		/* mask of enabled coprocessor types */
+#endif /* CONFIG_PPC_ICSWX */
 #ifdef CONFIG_PPC_MM_SLICES
 	u64 low_slices_psize;   /* SLB page size encodings */
 	u64 high_slices_psize;  /* 4 bits per slice for now */
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 9ec0b39..e927049 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -187,6 +187,10 @@
 #define SPRN_CSRR1	SPRN_SRR3 /* Critical Save and Restore Register 1 */
 #endif
 
+#ifdef CONFIG_PPC_ICSWX
+#define SPRN_HACOP	0x15F	/* Hypervisor Available Coprocessor Register */
+#endif
+
 /* Bit definitions for CCR1. */
 #define	CCR1_DPC	0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */
 #define	CCR1_TCS	0x00000080 /* Timer Clock Select */
diff --git a/arch/powerpc/kernel/cpu_setup_a2.S b/arch/powerpc/kernel/cpu_setup_a2.S
index 7f818fe..ebc62f4 100644
--- a/arch/powerpc/kernel/cpu_setup_a2.S
+++ b/arch/powerpc/kernel/cpu_setup_a2.S
@@ -41,11 +41,16 @@ _GLOBAL(__setup_cpu_a2)
 	 * core local but doing it always won't hurt
 	 */
 
-#ifdef CONFIG_PPC_WSP_COPRO
+#ifdef CONFIG_PPC_ICSWX
 	/* Make sure ACOP starts out as zero */
 	li	r3,0
 	mtspr   SPRN_ACOP,r3
 
+	/* Skip the following if we are in Guest mode */
+	mfmsr	r3
+	andis.	r0,r3,MSR_GS@h
+	bne	_icswx_skip_guest
+
 	/* Enable icswx instruction */
 	mfspr   r3,SPRN_A2_CCR2
 	ori     r3,r3,A2_CCR2_ENABLE_ICSWX
@@ -54,7 +59,8 @@ _GLOBAL(__setup_cpu_a2)
 	/* Unmask all CTs in HACOP */
 	li      r3,-1
 	mtspr   SPRN_HACOP,r3
-#endif /* CONFIG_PPC_WSP_COPRO */
+_icswx_skip_guest:
+#endif /* CONFIG_PPC_ICSWX */
 
 	/* Enable doorbell */
 	mfspr   r3,SPRN_A2_CCR2
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 4868d1f..f71f5e0 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -236,7 +236,7 @@ config VSX
 
 config PPC_ICSWX
 	bool "Support for PowerPC icswx coprocessor instruction"
-	depends on POWER4
+	depends on POWER4 || PPC_A2
 	default n
 	---help---
 
diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig
index f4fb837..ea2811c 100644
--- a/arch/powerpc/platforms/wsp/Kconfig
+++ b/arch/powerpc/platforms/wsp/Kconfig
@@ -1,6 +1,7 @@
 config PPC_WSP
 	bool
 	select PPC_A2
+	select PPC_ICSWX
 	select PPC_SCOM
 	select PPC_XICS
 	select PPC_ICP_NATIVE
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3 v3] powerpc: icswx: Simple ACOP fault handler for both book3e and book3s parts.
  2011-09-29  7:02   ` Benjamin Herrenschmidt
  2011-09-29 20:55     ` [PATCH 1/3 v3] " Jimi Xenidis
  2011-09-29 20:55     ` [PATCH 2/3 v3] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2 Jimi Xenidis
@ 2011-09-29 20:55     ` Jimi Xenidis
  2 siblings, 0 replies; 8+ messages in thread
From: Jimi Xenidis @ 2011-09-29 20:55 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anton Blanchard

This patch adds a fault handler that responds to illegal Coprocessor
types.  Currently all CTs are treated and illegal.  There are two ways
to report the fault back to the application.  If the application used
the record form ("icswx.") then the architected "reject" is emulated.
If the application did not used the record form ("icswx") then it is
selectable by config whether the failure is silent (as architected) or
a SIGILL is generated.

In all cases pr_warn() is used to log the bad CT.

Signed-off-by: Jimi Xenidis <jimix@pobox.com>

---
Re: galak@kernel.crashing.org
    - Fix Kconfig/CONFIG mismatch
    - Removed union/bitfields and inspect the bits directly
Re: benh@kernel.crashing.org
    rebase
---
 arch/powerpc/mm/fault.c                |   17 +++++
 arch/powerpc/mm/icswx.c                |  113 ++++++++++++++++++++++++++++++++
 arch/powerpc/mm/icswx.h                |   23 +++++++
 arch/powerpc/platforms/Kconfig.cputype |   13 ++++-
 4 files changed, 165 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 5efe8c9..2f0d1b0 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -44,6 +44,8 @@
 #include <asm/siginfo.h>
 #include <mm/mmu_decl.h>
 
+#include "icswx.h"
+
 #ifdef CONFIG_KPROBES
 static inline int notify_page_fault(struct pt_regs *regs)
 {
@@ -143,6 +145,21 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
 	is_write = error_code & ESR_DST;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
+#ifdef CONFIG_PPC_ICSWX
+	/*
+	 * we need to do this early because this "data storage
+	 * interrupt" does not update the DAR/DEAR so we don't want to
+	 * look at it
+	 */
+	if (error_code & ICSWX_DSI_UCT) {
+		int ret;
+
+		ret = acop_handle_fault(regs, address, error_code);
+		if (ret)
+			return ret;
+	}
+#endif
+
 	if (notify_page_fault(regs))
 		return 0;
 
diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
index a98850f..5d9a59e 100644
--- a/arch/powerpc/mm/icswx.c
+++ b/arch/powerpc/mm/icswx.c
@@ -17,6 +17,8 @@
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
+
 #include "icswx.h"
 
 /*
@@ -158,3 +160,114 @@ void drop_cop(unsigned long acop, struct mm_struct *mm)
 	spin_unlock(&mm->page_table_lock);
 }
 EXPORT_SYMBOL_GPL(drop_cop);
+
+static int acop_use_cop(int ct)
+{
+	/* todo */
+	return -1;
+}
+
+/*
+ * Get the instruction word at the NIP
+ */
+static u32 acop_get_inst(struct pt_regs *regs)
+{
+	u32 inst;
+	u32 __user *p;
+
+	p = (u32 __user *)regs->nip;
+	if (!access_ok(VERIFY_READ, p, sizeof(*p)))
+		return 0;
+
+	if (__get_user(inst, p))
+		return 0;
+
+	return inst;
+}
+
+/**
+ * @regs: regsiters at time of interrupt
+ * @address: storage address
+ * @error_code: Fault code, usually the DSISR or ESR depending on
+ *		processor type
+ *
+ * Return 0 if we are able to resolve the data storage fault that
+ * results from a CT miss in the ACOP register.
+ */
+int acop_handle_fault(struct pt_regs *regs, unsigned long address,
+		      unsigned long error_code)
+{
+	int ct;
+	u32 inst = 0;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX)) {
+		pr_info("No coprocessors available");
+		_exception(SIGILL, regs, ILL_ILLOPN, address);
+	}
+
+	if (!user_mode(regs)) {
+		/* this could happen if the HV denies the
+		 * kernel access, for now we just die */
+		die("ICSWX from kernel failed", regs, SIGSEGV);
+	}
+
+	/* Some implementations leave us a hint for the CT */
+	ct = ICSWX_GET_CT_HINT(error_code);
+	if (ct < 0) {
+		/* we have to peek at the instruction word to figure out CT */
+		u32 ccw;
+		u32 rs;
+
+		inst = acop_get_inst(regs);
+		if (inst == 0)
+			return -1;
+
+		rs = (inst >> (31 - 10)) & 0x1f;
+		ccw = regs->gpr[rs];
+		ct = (ccw >> 16) & 0x3f;
+	}
+
+	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",
+		current->comm, current->pid, ct);
+
+	/* get inst if we don't already have it */
+	if (inst == 0) {
+		inst = acop_get_inst(regs);
+		if (inst == 0)
+			return -1;
+	}
+
+	/* Check if the instruction is the "record form" */
+	if (inst & 1) {
+		/*
+		 * the instruction is "record" form so we can reject
+		 * using CR0
+		 */
+		regs->ccr &= ~(0xful << 28);
+		regs->ccr |= ICSWX_RC_NOT_FOUND << 28;
+
+		/* Move on to the next instruction */
+		regs->nip += 4;
+	} else {
+		/*
+		 * There is no architected mechanism to report a bad
+		 * CT so we could either SIGILL or report nothing.
+		 * Since the non-record version should only bu used
+		 * for "hints" or "don't care" we should probably do
+		 * nothing.  However, I could see how some people
+		 * might want an SIGILL so it here if you want it.
+		 */
+#ifdef CONFIG_PPC_ICSWX_USE_SIGILL
+		_exception(SIGILL, regs, ILL_ILLOPN, address);
+#else
+		regs->nip += 4;
+#endif
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(acop_handle_fault);
diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
index 07514e4..42176bd 100644
--- a/arch/powerpc/mm/icswx.h
+++ b/arch/powerpc/mm/icswx.h
@@ -36,4 +36,27 @@ extern void free_cop_pid(int free_pid);
 #define free_cop_pid(p)
 #endif
 
+/*
+ * These are implementation bits for architected registers.  If this
+ * ever becomes architecture the should be moved to reg.h et. al.
+ */
+/* UCT is the same bit for Server and Embedded */
+#define ICSWX_DSI_UCT		0x00004000  /* Unavailable Coprocessor Type */
+
+#ifdef CONFIG_PPC_BOOK3E
+/* Embedded implementation gives us no hints as to what the CT is */
+#define ICSWX_GET_CT_HINT(x) (-1)
+#else
+/* Server implementation contains the CT value in the DSISR */
+#define ICSWX_DSISR_CTMASK	0x00003f00
+#define ICSWX_GET_CT_HINT(x)	(((x) & ICSWX_DSISR_CTMASK) >> 8)
+#endif
+
+#define ICSWX_RC_STARTED	0x8	/* The request has been started */
+#define ICSWX_RC_NOT_IDLE	0x4	/* No coprocessor found idle */
+#define ICSWX_RC_NOT_FOUND	0x2	/* No coprocessor found */
+#define ICSWX_RC_UNDEFINED	0x1	/* Reserved */
+
+extern int acop_handle_fault(struct pt_regs *regs, unsigned long address,
+			     unsigned long error_code);
 #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index f71f5e0..f0d2e31 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -257,9 +257,20 @@ config PPC_ICSWX_PID
 	depends on PPC_ICSWX && POWER4
 	default y
 	---help---
-	  PID register in server is used explicitly for ICSWX.  In
+	  The PID register in server is used explicitly for ICSWX.  In
 	  embedded systems PID managment is done by the system.
 
+config PPC_ICSWX_USE_SIGILL
+	bool "Should a bad CT cause a SIGILL?"
+	depends on PPC_ICSWX
+	default n
+	---help---
+	  Should a bad CT used for "non-record form ICSWX" cause an
+	  illegal intruction signal or should it be silent as
+	  architected.
+
+	  If in doubt, say N here.
+
 config SPE
 	bool "SPE Support"
 	depends on E200 || (E500 && !PPC_E500MC)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-09-29 20:55 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-23 15:59 [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing Jimi Xenidis
2011-09-23 15:59 ` [PATCH 2/3 v2] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2 Jimi Xenidis
2011-09-23 15:59 ` [PATCH 3/3 v2] powerpc: icswx: Simple ACOP fault handler for both book3e and book3s parts Jimi Xenidis
2011-09-27 10:05 ` [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing Anton Blanchard
2011-09-29  7:02   ` Benjamin Herrenschmidt
2011-09-29 20:55     ` [PATCH 1/3 v3] " Jimi Xenidis
2011-09-29 20:55     ` [PATCH 2/3 v3] powerpc: book3e: Add ICSWX/ACOP support to Book3e cores like A2 Jimi Xenidis
2011-09-29 20:55     ` [PATCH 3/3 v3] powerpc: icswx: Simple ACOP fault handler for both book3e and book3s parts Jimi Xenidis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.