From patchwork Wed Oct 20 04:02:20 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Tseng-Hui (Frank) Lin" X-Patchwork-Id: 68388 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from bilbo.ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id 06729B72EE for ; Wed, 20 Oct 2010 15:08:25 +1100 (EST) Received: by ozlabs.org (Postfix) id 1008CB70A9; Wed, 20 Oct 2010 15:08:16 +1100 (EST) Delivered-To: linuxppc-dev@ozlabs.org Received: from e3.ny.us.ibm.com (e3.ny.us.ibm.com [32.97.182.143]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "e3.ny.us.ibm.com", Issuer "Equifax" (verified OK)) by ozlabs.org (Postfix) with ESMTPS id 15502B70A7 for ; Wed, 20 Oct 2010 15:08:11 +1100 (EST) Received: from d01relay02.pok.ibm.com (d01relay02.pok.ibm.com [9.56.227.234]) by e3.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id o9K3jeNC000801 for ; Tue, 19 Oct 2010 23:45:40 -0400 Received: from d03av05.boulder.ibm.com (d03av05.boulder.ibm.com [9.17.195.85]) by d01relay02.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o9K42Mr2400928 for ; Wed, 20 Oct 2010 00:02:26 -0400 Received: from d03av05.boulder.ibm.com (loopback [127.0.0.1]) by d03av05.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id o9K42LHk006328 for ; Tue, 19 Oct 2010 22:02:21 -0600 Received: from [9.53.40.45] (flin.austin.ibm.com [9.53.40.45]) by d03av05.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id o9K42LR4006319; Tue, 19 Oct 2010 22:02:21 -0600 Subject: [PATCH v3] add icswx support From: "Tseng-Hui (Frank) Lin" To: linuxppc-dev@ozlabs.org Date: Tue, 19 Oct 2010 23:02:20 -0500 Message-ID: <1287547340.14049.25.camel@flin.austin.ibm.com> Mime-Version: 1.0 X-Mailer: Evolution 2.28.3 (2.28.3-1.fc12) Cc: tsenglin@us.ibm.com X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org 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 Signed-off-by: Tseng-Hui (Frank) Lin --- 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(0x0200000000000000) #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 control */ /* 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 #include #include +#include #include #include @@ -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)