[PATCH v3] add icswx support
Michael Neuling
mikey at neuling.org
Tue Nov 2 08:11:24 EST 2010
In message <1287547340.14049.25.camel at flin.austin.ibm.com> you wrote:
> icswx is a PowerPC co-processor instruction to send data to a
> co-processor. On Book-S processors the LPAR_ID and process ID (PID) of
> the owning process are registered in the window context of the
> co-processor at initial time. When the icswx instruction is executed,
> the L2 generates a cop-reg transaction on PowerBus. The transaction has
> no address and the processor does not perform an MMU access to
> authenticate the transaction. The coprocessor compares the LPAR_ID and
> the PID included in the transaction and the LPAR_ID and PID held in the
> window context to determine if the process is authorized to generate the
> transaction.
>
> The OS needs to assign a 16-bit PID for the process. This cop-PID needs
> to be updated during context switch. The cop-PID needs to be destroyed
> when the context is destroyed.
>
> Change log from v2:
> - Make the code a CPU feature and return -NODEV if CPU doesn't have
> icswx co-processor instruction.
> - Change the goto loop in use_cop() into a do-while loop.
> - Change context destroy code into a new destroy_context_acop() function
> and #define it based on CONFIG_ICSWX.
> - Remove mmput() from drop_cop().
> - Fix some TAB/space problems.
>
> Signed-off-by: Sonny Rao <sonnyrao at linux.vnet.ibm.com>
> Signed-off-by: Tseng-Hui (Frank) Lin <thlin at linux.vnet.ibm.com>
This is white space munged again.
Mikey
>
> ---
> arch/powerpc/include/asm/cputable.h | 4 +-
> arch/powerpc/include/asm/mmu-hash64.h | 5 ++
> arch/powerpc/include/asm/mmu_context.h | 6 ++
> arch/powerpc/include/asm/reg.h | 11 +++
> arch/powerpc/include/asm/reg_booke.h | 3 -
> arch/powerpc/mm/mmu_context_hash64.c | 109
> ++++++++++++++++++++++++++++++++
> arch/powerpc/platforms/Kconfig.cputype | 17 +++++
> 7 files changed, 151 insertions(+), 4 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/cputable.h
> b/arch/powerpc/include/asm/cputable.h
> index 3a40a99..bbb4e2c 100644
> --- a/arch/powerpc/include/asm/cputable.h
> +++ b/arch/powerpc/include/asm/cputable.h
> @@ -198,6 +198,7 @@ extern const char *powerpc_base_platform;
> #define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000)
> #define CPU_FTR_UNALIGNED_LD_STD LONG_ASM_CONST(0x0080000000000000)
> #define CPU_FTR_ASYM_SMT LONG_ASM_CONST(0x0100000000000000)
> +#define CPU_FTR_ICSWX LONG_ASM_CONST(0x02000000000000
00)
>
> #ifndef __ASSEMBLY__
>
> @@ -413,7 +414,8 @@ extern const char *powerpc_base_platform;
> CPU_FTR_MMCRA | CPU_FTR_SMT | \
> CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
> CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
> - CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT)
> + CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \
> + CPU_FTR_ICSWX)
> #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
> CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
> CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
> diff --git a/arch/powerpc/include/asm/mmu-hash64.h
> b/arch/powerpc/include/asm/mmu-hash64.h
> index acac35d..6c1ab90 100644
> --- a/arch/powerpc/include/asm/mmu-hash64.h
> +++ b/arch/powerpc/include/asm/mmu-hash64.h
> @@ -423,6 +423,11 @@ typedef struct {
> #ifdef CONFIG_PPC_SUBPAGE_PROT
> struct subpage_prot_table spt;
> #endif /* CONFIG_PPC_SUBPAGE_PROT */
> +#ifdef CONFIG_ICSWX
> + unsigned long acop; /* mask of enabled coprocessor types */
> +#define HASH64_MAX_PID (0xFFFF)
> + unsigned int acop_pid; /* pid value used with coprocessors */
> +#endif /* CONFIG_ICSWX */
> } mm_context_t;
>
>
> diff --git a/arch/powerpc/include/asm/mmu_context.h
> b/arch/powerpc/include/asm/mmu_context.h
> index 81fb412..88118de 100644
> --- a/arch/powerpc/include/asm/mmu_context.h
> +++ b/arch/powerpc/include/asm/mmu_context.h
> @@ -80,6 +80,12 @@ static inline void switch_mm(struct mm_struct *prev,
> struct mm_struct *next,
>
> #define deactivate_mm(tsk,mm) do { } while (0)
>
> +#ifdef CONFIG_ICSWX
> +extern void switch_cop(struct mm_struct *next);
> +extern int use_cop(unsigned long acop, struct mm_struct *mm);
> +extern void drop_cop(unsigned long acop, struct mm_struct *mm);
> +#endif /* CONFIG_ICSWX */
> +
> /*
> * After we have set current->mm to a new value, this activates
> * the context for the new mm so we see the new mappings.
> diff --git a/arch/powerpc/include/asm/reg.h
> b/arch/powerpc/include/asm/reg.h
> index ff0005eec..b86d876 100644
> --- a/arch/powerpc/include/asm/reg.h
> +++ b/arch/powerpc/include/asm/reg.h
> @@ -170,8 +170,19 @@
> #define SPEFSCR_FRMC 0x00000003 /* Embedded FP rounding mode co
ntrol
> */
>
> /* Special Purpose Registers (SPRNs)*/
> +
> +#ifdef CONFIG_40x
> +#define SPRN_PID 0x3B1 /* Process ID */
> +#else
> +#define SPRN_PID 0x030 /* Process ID */
> +#ifdef CONFIG_BOOKE
> +#define SPRN_PID0 SPRN_PID/* Process ID Register 0 */
> +#endif
> +#endif
> +
> #define SPRN_CTR 0x009 /* Count Register */
> #define SPRN_DSCR 0x11
> +#define SPRN_ACOP 0x1F /* Available Coprocessor Register */
> #define SPRN_CTRLF 0x088
> #define SPRN_CTRLT 0x098
> #define CTRL_CT 0xc0000000 /* current thread */
> diff --git a/arch/powerpc/include/asm/reg_booke.h
> b/arch/powerpc/include/asm/reg_booke.h
> index 667a498..5b0c781 100644
> --- a/arch/powerpc/include/asm/reg_booke.h
> +++ b/arch/powerpc/include/asm/reg_booke.h
> @@ -150,8 +150,6 @@
> * or IBM 40x.
> */
> #ifdef CONFIG_BOOKE
> -#define SPRN_PID 0x030 /* Process ID */
> -#define SPRN_PID0 SPRN_PID/* Process ID Register 0 */
> #define SPRN_CSRR0 0x03A /* Critical Save and Restore Register 0 */
> #define SPRN_CSRR1 0x03B /* Critical Save and Restore Register 1 */
> #define SPRN_DEAR 0x03D /* Data Error Address Register */
> @@ -168,7 +166,6 @@
> #define SPRN_TCR 0x154 /* Timer Control Register */
> #endif /* Book E */
> #ifdef CONFIG_40x
> -#define SPRN_PID 0x3B1 /* Process ID */
> #define SPRN_DBCR1 0x3BD /* Debug Control Register 1 */
> #define SPRN_ESR 0x3D4 /* Exception Syndrome Register */
> #define SPRN_DEAR 0x3D5 /* Data Error Address Register */
> diff --git a/arch/powerpc/mm/mmu_context_hash64.c
> b/arch/powerpc/mm/mmu_context_hash64.c
> index 2535828..6ef6ce2 100644
> --- a/arch/powerpc/mm/mmu_context_hash64.c
> +++ b/arch/powerpc/mm/mmu_context_hash64.c
> @@ -18,6 +18,7 @@
> #include <linux/mm.h>
> #include <linux/spinlock.h>
> #include <linux/idr.h>
> +#include <linux/percpu.h>
> #include <linux/module.h>
> #include <linux/gfp.h>
>
> @@ -26,6 +27,113 @@
> static DEFINE_SPINLOCK(mmu_context_lock);
> static DEFINE_IDA(mmu_context_ida);
>
> +#ifdef CONFIG_ICSWX
> +static DEFINE_SPINLOCK(mmu_context_acop_lock);
> +static DEFINE_IDA(cop_ida);
> +
> +/* Lazy switch the ACOP register */
> +static DEFINE_PER_CPU(unsigned long, acop_reg);
> +
> +void switch_cop(struct mm_struct *next)
> +{
> + if (!cpu_has_feature(CPU_FTR_ICSWX))
> + return;
> +
> + mtspr(SPRN_PID, next->context.acop_pid);
> + if (next->context.acop_pid &&
> + __get_cpu_var(acop_reg) != next->context.acop) {
> + mtspr(SPRN_ACOP, next->context.acop);
> + __get_cpu_var(acop_reg) = next->context.acop;
> + }
> +}
> +EXPORT_SYMBOL(switch_cop);
> +
> +int use_cop(unsigned long acop, struct mm_struct *mm)
> +{
> + int acop_pid;
> + int err;
> +
> + if (!cpu_has_feature(CPU_FTR_ICSWX))
> + return -ENODEV;
> +
> + if (!mm)
> + return -EINVAL;
> +
> + if (!mm->context.acop_pid) {
> + if (!ida_pre_get(&cop_ida, GFP_KERNEL))
> + return -ENOMEM;
> + do {
> + spin_lock(&mmu_context_acop_lock);
> + err = ida_get_new_above(&cop_ida, 1, &acop_pid);
> + spin_unlock(&mmu_context_acop_lock);
> + } while (err == -EAGAIN);
> +
> + if (err)
> + return err;
> +
> + if (acop_pid > HASH64_MAX_PID) {
> + spin_lock(&mmu_context_acop_lock);
> + ida_remove(&cop_ida, acop_pid);
> + spin_unlock(&mmu_context_acop_lock);
> + return -EBUSY;
> + }
> + mm->context.acop_pid = acop_pid;
> + if (mm == current->active_mm)
> + mtspr(SPRN_PID, mm->context.acop_pid);
> + }
> + spin_lock(&mmu_context_acop_lock);
> + mm->context.acop |= acop;
> + spin_unlock(&mmu_context_acop_lock);
> +
> + get_cpu_var(acop_reg) = mm->context.acop;
> + if (mm == current->active_mm)
> + mtspr(SPRN_ACOP, mm->context.acop);
> + put_cpu_var(acop_reg);
> +
> + return mm->context.acop_pid;
> +}
> +EXPORT_SYMBOL(use_cop);
> +
> +void drop_cop(unsigned long acop, struct mm_struct *mm)
> +{
> + if (!cpu_has_feature(CPU_FTR_ICSWX))
> + return;
> +
> + if (WARN_ON(!mm))
> + return;
> +
> + spin_lock(&mmu_context_acop_lock);
> + mm->context.acop &= ~acop;
> + spin_unlock(&mmu_context_acop_lock);
> + if (!mm->context.acop) {
> + spin_lock(&mmu_context_acop_lock);
> + ida_remove(&cop_ida, mm->context.acop_pid);
> + spin_unlock(&mmu_context_acop_lock);
> + mm->context.acop_pid = 0;
> + if (mm == current->active_mm)
> + mtspr(SPRN_PID, mm->context.acop_pid);
> + } else {
> + get_cpu_var(acop_reg) = mm->context.acop;
> + if (mm == current->active_mm)
> + mtspr(SPRN_ACOP, mm->context.acop);
> + put_cpu_var(acop_reg);
> + }
> +}
> +EXPORT_SYMBOL(drop_cop);
> +
> +static void destroy_context_acop(struct mm_struct *mm)
> +{
> + if (mm->context.acop_pid) {
> + spin_lock(&mmu_context_acop_lock);
> + ida_remove(&cop_ida, mm->context.acop_pid);
> + spin_unlock(&mmu_context_acop_lock);
> + }
> +}
> +
> +#else
> +#define destroy_context_acop(mm)
> +#endif /* CONFIG_ICSWX */
> +
> /*
> * The proto-VSID space has 2^35 - 1 segments available for user
> mappings.
> * Each segment contains 2^28 bytes. Each context maps 2^44 bytes,
> @@ -93,6 +201,7 @@ EXPORT_SYMBOL_GPL(__destroy_context);
>
> void destroy_context(struct mm_struct *mm)
> {
> + destroy_context_acop(mm);
> __destroy_context(mm->context.id);
> subpage_prot_free(mm);
> mm->context.id = NO_CONTEXT;
> diff --git a/arch/powerpc/platforms/Kconfig.cputype
> b/arch/powerpc/platforms/Kconfig.cputype
> index d361f81..7678e29 100644
> --- a/arch/powerpc/platforms/Kconfig.cputype
> +++ b/arch/powerpc/platforms/Kconfig.cputype
> @@ -220,6 +220,23 @@ config VSX
>
> If in doubt, say Y here.
>
> +config ICSWX
> + bool "Support for PowerPC icswx co-processor instruction"
> + depends on POWER4
> + default n
> + ---help---
> +
> + Enabling this option to turn on the PowerPC icswx co-processor
> + instruction support for POWER7 or newer processors.
> + This option is only useful if you have a processor that supports
> + icswx co-processor instruction. It does not have any effect on
> + processors without icswx co-processor instruction.
> +
> + This support slightly increases kernel memory usage.
> +
> + Say N if you do not have a PowerPC processor supporting icswx
> + instruction and a PowerPC co-processor.
> +
> config SPE
> bool "SPE Support"
> depends on E200 || (E500 && !PPC_E500MC)
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
More information about the Linuxppc-dev
mailing list