Message ID | 1286855108.14049.8.camel@flin.austin.ibm.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
In message <1286855108.14049.8.camel@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. > > This patch adds icswx co-processor instruction support. Can you describe the ABI a bit? How has this changed from version 1? Patch has been whitespace munged aswell. More comments below... > > Signed-off-by: Sonny Rao <sonnyrao@linux.vnet.ibm.com> > Signed-off-by: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com> > --- > arch/powerpc/include/asm/mmu-hash64.h | 5 ++ > arch/powerpc/include/asm/mmu_context.h | 6 ++ > arch/powerpc/include/asm/reg.h | 12 ++++ > arch/powerpc/include/asm/reg_booke.h | 3 - > arch/powerpc/mm/mmu_context_hash64.c | 105 > ++++++++++++++++++++++++++++++++ > arch/powerpc/platforms/Kconfig.cputype | 16 +++++ > 6 files changed, 144 insertions(+), 3 deletions(-) > > 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..9bbf178 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 > + Why are you moving these definitions? > #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 */ > @@ -879,6 +890,7 @@ > #define PV_POWER5 0x003A > #define PV_POWER5p 0x003B > #define PV_970FX 0x003C > +#define PV_POWER7 0x003F > #define PV_630 0x0040 > #define PV_630p 0x0041 > #define PV_970MP 0x0044 > 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..8f432b6 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,103 @@ > 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 (!__is_processor(PV_POWER7)) > + 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 (!__is_processor(PV_POWER7)) > + return -ENOSYS; This should be a CPU feature. > + > + if (!mm) > + return -EINVAL; > + > + if (!mm->context.acop_pid) { > + if (!ida_pre_get(&cop_ida, GFP_KERNEL)) > + return -ENOMEM; > +again: > + spin_lock(&mmu_context_acop_lock); > + err = ida_get_new_above(&cop_ida, 1, &acop_pid); > + spin_unlock(&mmu_context_acop_lock); > + > + if (err == -EAGAIN) > + goto again; Make this a do while loop. Please don't create your own loop prematives. > + else 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 (!__is_processor(PV_POWER7)) > + 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); > + } > + mmput(mm); > +} > +EXPORT_SYMBOL(drop_cop); > +#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 +191,13 @@ EXPORT_SYMBOL_GPL(__destroy_context); > > void destroy_context(struct mm_struct *mm) > { > +#ifdef CONFIG_ICSWX > + 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); > + } > +#endif /* CONFIG_ICSWX */ Can you put this in a destroy_context_acop() and #define that funtion based CONFIG_ICSWX. Cleans up the #ifdefs here > __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..9674703 100644 > --- a/arch/powerpc/platforms/Kconfig.cputype > +++ b/arch/powerpc/platforms/Kconfig.cputype > @@ -220,6 +220,22 @@ 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 processors. > + This option is only useful if you have a processor that supports > + icswx co-processor instruction. It does not have any affect on > + processors without icswx co-processor instruction. > + > + This support slightly increases kernel memory usage. > + > + Say N if you do not have a POWER7 processor and a PowerPC > co-processor. > + > config SPE > bool "SPE Support" > depends on E200 || (E500 && !PPC_E500MC) > > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev >
On Wed, 2010-10-13 at 11:52 +1100, Michael Neuling wrote: > In message <1286855108.14049.8.camel@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. > > > > This patch adds icswx co-processor instruction support. > > Can you describe the ABI a bit? > > How has this changed from version 1? > The icswx instruction itself does nothing but generating a cop-req transaction on PowerBus. The cop-req transaction causes 1 cache line of data (128 bytes) sent to the co-processor. This provides a low latency mechanism for sending small amount of data without the co-processor becoming a master on the PowerBus. Since the transaction has no address and the processor does not perform an MMU access to authenticate the transaction, the co-processor relys on the the LPAR_ID and PID 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 needs to be updated during context switch. The cop-PID needs to be destroied when the context is destroied. Change log from v1: - Change 2'nd parameter of use_cop() from struct task_struct *task to struct mm_struct *mm. - Check for mm == current->active_mm before calling mtspr(). - Add a lock to guard acop related operations. - Check for POWER7 CPU. - Move the definition of SPRN_PID from reg_booke.h to avoid defining SPRN_PID in two different files. - Rename pid to acop_pid. - Change function name disuse_cop() to drop_cop(). - Add a comment to describe the two new fields in mm_context_t. - Moving CONFIG_ICSWX from arch/powerpc/platforms/pseries/Kconfig to arch/powerpc/platforms/Kconfig.cputype All other comments will be addressed in a new patch. > Patch has been whitespace munged aswell. > > More comments below... > > > > > Signed-off-by: Sonny Rao <sonnyrao@linux.vnet.ibm.com> > > Signed-off-by: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com> > > --- > > arch/powerpc/include/asm/mmu-hash64.h | 5 ++ > > arch/powerpc/include/asm/mmu_context.h | 6 ++ > > arch/powerpc/include/asm/reg.h | 12 ++++ > > arch/powerpc/include/asm/reg_booke.h | 3 - > > arch/powerpc/mm/mmu_context_hash64.c | 105 > > ++++++++++++++++++++++++++++++++ > > arch/powerpc/platforms/Kconfig.cputype | 16 +++++ > > 6 files changed, 144 insertions(+), 3 deletions(-) > > > > 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..9bbf178 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 > > + > > Why are you moving these definitions? > > > #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 */ > > @@ -879,6 +890,7 @@ > > #define PV_POWER5 0x003A > > #define PV_POWER5p 0x003B > > #define PV_970FX 0x003C > > +#define PV_POWER7 0x003F > > #define PV_630 0x0040 > > #define PV_630p 0x0041 > > #define PV_970MP 0x0044 > > 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..8f432b6 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,103 @@ > > 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 (!__is_processor(PV_POWER7)) > > + 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 (!__is_processor(PV_POWER7)) > > + return -ENOSYS; > > This should be a CPU feature. > > > + > > + if (!mm) > > + return -EINVAL; > > + > > + if (!mm->context.acop_pid) { > > + if (!ida_pre_get(&cop_ida, GFP_KERNEL)) > > + return -ENOMEM; > > +again: > > + spin_lock(&mmu_context_acop_lock); > > + err = ida_get_new_above(&cop_ida, 1, &acop_pid); > > + spin_unlock(&mmu_context_acop_lock); > > + > > + if (err == -EAGAIN) > > + goto again; > > Make this a do while loop. Please don't create your own loop > prematives. > > > + else 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 (!__is_processor(PV_POWER7)) > > + 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); > > + } > > + mmput(mm); > > +} > > +EXPORT_SYMBOL(drop_cop); > > +#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 +191,13 @@ EXPORT_SYMBOL_GPL(__destroy_context); > > > > void destroy_context(struct mm_struct *mm) > > { > > +#ifdef CONFIG_ICSWX > > + 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); > > + } > > +#endif /* CONFIG_ICSWX */ > > Can you put this in a destroy_context_acop() and #define that funtion > based CONFIG_ICSWX. Cleans up the #ifdefs here > > > > __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..9674703 100644 > > --- a/arch/powerpc/platforms/Kconfig.cputype > > +++ b/arch/powerpc/platforms/Kconfig.cputype > > @@ -220,6 +220,22 @@ 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 processors. > > + This option is only useful if you have a processor that supports > > + icswx co-processor instruction. It does not have any affect on > > + processors without icswx co-processor instruction. > > + > > + This support slightly increases kernel memory usage. > > + > > + Say N if you do not have a POWER7 processor and a PowerPC > > co-processor. > > + > > config SPE > > bool "SPE Support" > > depends on E200 || (E500 && !PPC_E500MC) > > > > > > _______________________________________________ > > Linuxppc-dev mailing list > > Linuxppc-dev@lists.ozlabs.org > > https://lists.ozlabs.org/listinfo/linuxppc-dev > > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev
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..9bbf178 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 */ @@ -879,6 +890,7 @@ #define PV_POWER5 0x003A #define PV_POWER5p 0x003B #define PV_970FX 0x003C +#define PV_POWER7 0x003F #define PV_630 0x0040 #define PV_630p 0x0041 #define PV_970MP 0x0044 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..8f432b6 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,103 @@ 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 (!__is_processor(PV_POWER7)) + 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 (!__is_processor(PV_POWER7)) + return -ENOSYS; + + if (!mm) + return -EINVAL; + + if (!mm->context.acop_pid) { + if (!ida_pre_get(&cop_ida, GFP_KERNEL)) + return -ENOMEM; +again: + spin_lock(&mmu_context_acop_lock); + err = ida_get_new_above(&cop_ida, 1, &acop_pid); + spin_unlock(&mmu_context_acop_lock); + + if (err == -EAGAIN) + goto again; + else 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 (!__is_processor(PV_POWER7)) + 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); + } + mmput(mm); +} +EXPORT_SYMBOL(drop_cop); +#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 +191,13 @@ EXPORT_SYMBOL_GPL(__destroy_context); void destroy_context(struct mm_struct *mm) { +#ifdef CONFIG_ICSWX + 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); + } +#endif /* CONFIG_ICSWX */ __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..9674703 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -220,6 +220,22 @@ 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 processors. + This option is only useful if you have a processor that supports + icswx co-processor instruction. It does not have any affect on + processors without icswx co-processor instruction. + + This support slightly increases kernel memory usage. + + Say N if you do not have a POWER7 processor and a PowerPC co-processor. + config SPE bool "SPE Support"