* [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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).