* [PATCH 3/3] powerpc, ptrace: Add new ptrace request macro for miscellaneous registers
From: Anshuman Khandual @ 2014-04-02 7:02 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel; +Cc: mikey, avagin, oleg, roland, Anshuman Khandual
In-Reply-To: <1396422144-11032-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch adds following new set of ptrace request macros for miscellaneous
registers expanding the existing ptrace ABI on PowerPC.
/* Miscellaneous registers */
PTRACE_GETMSCREGS
PTRACE_SETMSCREGS
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/include/uapi/asm/ptrace.h | 10 ++++
arch/powerpc/kernel/ptrace.c | 91 +++++++++++++++++++++++++++++++++-
2 files changed, 100 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/uapi/asm/ptrace.h b/arch/powerpc/include/uapi/asm/ptrace.h
index 1a12c36..bce1055 100644
--- a/arch/powerpc/include/uapi/asm/ptrace.h
+++ b/arch/powerpc/include/uapi/asm/ptrace.h
@@ -241,6 +241,16 @@ struct pt_regs {
#define PTRACE_GETTM_CVMXREGS 0x76
#define PTRACE_SETTM_CVMXREGS 0x77
+/* Miscellaneous registers */
+#define PTRACE_GETMSCREGS 0x78
+#define PTRACE_SETMSCREGS 0x79
+
+/*
+ * XXX: A note to application developers. The existing data layout
+ * of the above four ptrace requests can change when new registers
+ * are available for each category in forthcoming processors.
+ */
+
#ifndef __ASSEMBLY__
struct ppc_debug_info {
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 9fbcb6a..2893958 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1054,6 +1054,76 @@ static int tm_cvmx_set(struct task_struct *target, const struct user_regset *reg
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
/*
+ * Miscellaneous Registers
+ *
+ * struct {
+ * unsigned long dscr;
+ * unsigned long ppr;
+ * unsigned long tar;
+ * };
+ */
+static int misc_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ /* DSCR register */
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.dscr, 0,
+ sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
+ sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
+
+ /* PPR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.ppr, sizeof(unsigned long),
+ 2 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
+ != offsetof(struct thread_struct, tar));
+ /* TAR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tar, 2 * sizeof(unsigned long),
+ 3 * sizeof(unsigned long));
+ return ret;
+}
+
+static int misc_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ /* DSCR register */
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.dscr, 0,
+ sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, dscr) + sizeof(unsigned long) +
+ sizeof(unsigned long) != offsetof(struct thread_struct, ppr));
+
+ /* PPR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.ppr, sizeof(unsigned long),
+ 2 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, ppr) + sizeof(unsigned long)
+ != offsetof(struct thread_struct, tar));
+
+ /* TAR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tar, 2 * sizeof(unsigned long),
+ 3 * sizeof(unsigned long));
+ return ret;
+}
+
+/*
* These are our native regset flavors.
*/
enum powerpc_regset {
@@ -1072,8 +1142,9 @@ enum powerpc_regset {
REGSET_TM_SPR, /* TM specific SPR */
REGSET_TM_CGPR, /* TM checkpointed GPR */
REGSET_TM_CFPR, /* TM checkpointed FPR */
- REGSET_TM_CVMX /* TM checkpointed VMX */
+ REGSET_TM_CVMX, /* TM checkpointed VMX */
#endif
+ REGSET_MISC /* Miscellaneous */
};
static const struct user_regset native_regsets[] = {
@@ -1130,6 +1201,11 @@ static const struct user_regset native_regsets[] = {
.get = tm_cvmx_get, .set = tm_cvmx_set
},
#endif
+ [REGSET_MISC] = {
+ .core_note_type = NT_PPC_MISC, .n = 3,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = misc_get, .set = misc_set
+ },
};
static const struct user_regset_view user_ppc_native_view = {
@@ -1320,6 +1396,11 @@ static const struct user_regset compat_regsets[] = {
.get = tm_cvmx_get, .set = tm_cvmx_set
},
#endif
+ [REGSET_MISC] = {
+ .core_note_type = NT_PPC_MISC, .n = 3,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = misc_get, .set = misc_set
+ },
};
static const struct user_regset_view user_ppc_compat_view = {
@@ -2269,6 +2350,14 @@ long arch_ptrace(struct task_struct *child, long request,
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_TM_CVMX, 0, (33 * sizeof(vector128) + sizeof(u32)), datavp);
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+ case PTRACE_GETMSCREGS:
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_MISC, 0, 3 * sizeof(u64),
+ datavp);
+ case PTRACE_SETMSCREGS:
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_MISC, 0, 3 * sizeof(u64),
+ datavp);
default:
ret = ptrace_request(child, request, addr, data);
break;
--
1.7.11.7
^ permalink raw reply related
* [PATCH 2/3] powerpc, ptrace: Add new ptrace request macros for transactional memory
From: Anshuman Khandual @ 2014-04-02 7:02 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel; +Cc: mikey, avagin, oleg, roland, Anshuman Khandual
In-Reply-To: <1396422144-11032-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch adds following new sets of ptrace request macros for transactional
memory expanding the existing ptrace ABI on PowerPC.
/* TM special purpose registers */
PTRACE_GETTM_SPRREGS
PTRACE_SETTM_SPRREGS
/* TM checkpointed GPR registers */
PTRACE_GETTM_CGPRREGS
PTRACE_SETTM_CGPRREGS
/* TM checkpointed FPR registers */
PTRACE_GETTM_CFPRREGS
PTRACE_SETTM_CFPRREGS
/* TM checkpointed VMX registers */
PTRACE_GETTM_CVMXREGS
PTRACE_SETTM_CVMXREGS
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/switch_to.h | 8 +
arch/powerpc/include/uapi/asm/ptrace.h | 51 +++
arch/powerpc/kernel/process.c | 24 ++
arch/powerpc/kernel/ptrace.c | 570 +++++++++++++++++++++++++++++++--
4 files changed, 625 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 0e83e7d..22095e2 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -80,6 +80,14 @@ static inline void flush_spe_to_thread(struct task_struct *t)
}
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+extern void flush_tmreg_to_thread(struct task_struct *);
+#else
+static inline void flush_tmreg_to_thread(struct task_struct *t)
+{
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
static inline void clear_task_ebb(struct task_struct *t)
{
#ifdef CONFIG_PPC_BOOK3S_64
diff --git a/arch/powerpc/include/uapi/asm/ptrace.h b/arch/powerpc/include/uapi/asm/ptrace.h
index 77d2ed3..1a12c36 100644
--- a/arch/powerpc/include/uapi/asm/ptrace.h
+++ b/arch/powerpc/include/uapi/asm/ptrace.h
@@ -190,6 +190,57 @@ struct pt_regs {
#define PPC_PTRACE_SETHWDEBUG 0x88
#define PPC_PTRACE_DELHWDEBUG 0x87
+/* Transactional memory */
+
+/*
+ * TM specific SPR
+ *
+ * struct data {
+ * u64 tm_tfhar;
+ * u64 tm_texasr;
+ * u64 tm_tfiar;
+ * unsigned long tm_orig_msr;
+ * u64 tm_tar;
+ * u64 tm_ppr;
+ * u64 tm_dscr;
+ * };
+ */
+#define PTRACE_GETTM_SPRREGS 0x70
+#define PTRACE_SETTM_SPRREGS 0x71
+
+/*
+ * TM Checkpointed GPR
+ *
+ * struct data {
+ * struct pt_regs ckpt_regs;
+ * };
+ */
+#define PTRACE_GETTM_CGPRREGS 0x72
+#define PTRACE_SETTM_CGPRREGS 0x73
+
+/*
+ * TM Checkpointed FPR
+ *
+ * struct data {
+ * u64 fpr[32];
+ * u64 fpscr;
+ * };
+ */
+#define PTRACE_GETTM_CFPRREGS 0x74
+#define PTRACE_SETTM_CFPRREGS 0x75
+
+/*
+ * TM Checkpointed VMX
+ *
+ * struct data {
+ * vector128 vr[32];
+ * vector128 vscr;
+ * unsigned long vrsave;
+ *};
+ */
+#define PTRACE_GETTM_CVMXREGS 0x76
+#define PTRACE_SETTM_CVMXREGS 0x77
+
#ifndef __ASSEMBLY__
struct ppc_debug_info {
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index af064d2..230a0ee 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -673,6 +673,30 @@ static inline void __switch_to_tm(struct task_struct *prev)
}
}
+void flush_tmreg_to_thread(struct task_struct *tsk)
+{
+ /*
+ * If task is not current, it should have been flushed
+ * already to it's thread_struct during __switch_to().
+ */
+ if (tsk != current)
+ return;
+
+ preempt_disable();
+ if (tsk->thread.regs) {
+ /*
+ * If we are still current, the TM state need to
+ * be flushed to thread_struct as it will be still
+ * present in the current cpu
+ */
+ if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+ __switch_to_tm(tsk);
+ tm_recheckpoint_new_task(tsk);
+ }
+ }
+ preempt_enable();
+}
+
/*
* This is called if we are on the way out to userspace and the
* TIF_RESTORE_TM flag is set. It checks if we need to reload
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 2e3d2bf..9fbcb6a 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -357,6 +357,17 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
return ret;
}
+/*
+ * When any transaction is active, "thread_struct->transact_fp" holds
+ * the current running value of all FPR registers and "thread_struct->
+ * fp_state" holds the last checkpointed FPR registers state for the
+ * current transaction.
+ *
+ * struct data {
+ * u64 fpr[32];
+ * u64 fpscr;
+ * };
+ */
static int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
@@ -365,21 +376,41 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
u64 buf[33];
int i;
#endif
- flush_fp_to_thread(target);
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+ } else {
+ flush_fp_to_thread(target);
+ }
#ifdef CONFIG_VSX
/* copy to local buffer then write that out */
- for (i = 0; i < 32 ; i++)
- buf[i] = target->thread.TS_FPR(i);
- buf[32] = target->thread.fp_state.fpscr;
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.TS_TRANS_FPR(i);
+ buf[32] = target->thread.transact_fp.fpscr;
+ } else {
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.TS_FPR(i);
+ buf[32] = target->thread.fp_state.fpscr;
+ }
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
#else
- BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
- offsetof(struct thread_fp_state, fpr[32][0]));
+ if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) {
+ BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
+ offsetof(struct transact_fp, fpr[32][0]));
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.transact_fp, 0, -1);
+ } esle {
+ BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+ offsetof(struct thread_fp_state, fpr[32][0]));
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fp_state, 0, -1);
+ }
#endif
}
@@ -391,23 +422,44 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
u64 buf[33];
int i;
#endif
- flush_fp_to_thread(target);
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+ } else {
+ flush_fp_to_thread(target);
+ }
#ifdef CONFIG_VSX
/* copy to local buffer then write that out */
i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
if (i)
return i;
- for (i = 0; i < 32 ; i++)
- target->thread.TS_FPR(i) = buf[i];
- target->thread.fp_state.fpscr = buf[32];
+ for (i = 0; i < 32 ; i++) {
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ target->thread.TS_TRANS_FPR(i) = buf[i];
+ else
+ target->thread.TS_FPR(i) = buf[i];
+ }
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ target->thread.transact_fp.fpscr = buf[32];
+ else
+ target->thread.fp_state.fpscr = buf[32];
return 0;
#else
- BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
- offsetof(struct thread_fp_state, fpr[32][0]));
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ BUILD_BUG_ON(offsetof(struct transact_fp, fpscr) !=
+ offsetof(struct transact_fp, fpr[32][0]));
- return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.fp_state, 0, -1);
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.transact_fp, 0, -1);
+ } else {
+ BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+ offsetof(struct thread_fp_state, fpr[32][0]));
+
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fp_state, 0, -1);
+ }
#endif
}
@@ -432,20 +484,44 @@ static int vr_active(struct task_struct *target,
return target->thread.used_vr ? regset->n : 0;
}
+/*
+ * When any transaction is active, "thread_struct->transact_vr" holds
+ * the current running value of all VMX registers and "thread_struct->
+ * vr_state" holds the last checkpointed value of VMX registers for the
+ * current transaction.
+ *
+ * struct data {
+ * vector128 vr[32];
+ * vector128 vscr;
+ * vector128 vrsave;
+ * };
+ */
static int vr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
int ret;
+ struct thread_vr_state *addr;
- flush_altivec_to_thread(target);
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+ } else {
+ flush_altivec_to_thread(target);
+ }
BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
offsetof(struct thread_vr_state, vr[32]));
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ addr = &target->thread.transact_vr;
+ else
+ addr = &target->thread.vr_state;
+
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.vr_state, 0,
- 33 * sizeof(vector128));
+ addr, 0, 33 * sizeof(vector128));
+
if (!ret) {
/*
* Copy out only the low-order word of vrsave.
@@ -455,11 +531,14 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
u32 word;
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
- vrsave.word = target->thread.vrsave;
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ vrsave.word = target->thread.transact_vrsave;
+ else
+ vrsave.word = target->thread.vrsave;
+
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
}
-
return ret;
}
@@ -467,16 +546,27 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
+ struct thread_vr_state *addr;
int ret;
- flush_altivec_to_thread(target);
+ if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+ } else {
+ flush_altivec_to_thread(target);
+ }
BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
offsetof(struct thread_vr_state, vr[32]));
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ addr = &target->thread.transact_vr;
+ else
+ addr = &target->thread.vr_state;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.vr_state, 0,
- 33 * sizeof(vector128));
+ addr, 0, 33 * sizeof(vector128));
+
if (!ret && count > 0) {
/*
* We use only the first word of vrsave.
@@ -486,13 +576,21 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
u32 word;
} vrsave;
memset(&vrsave, 0, sizeof(vrsave));
- vrsave.word = target->thread.vrsave;
+
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ vrsave.word = target->thread.transact_vrsave;
+ else
+ vrsave.word = target->thread.vrsave;
+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
33 * sizeof(vector128), -1);
- if (!ret)
- target->thread.vrsave = vrsave.word;
+ if (!ret) {
+ if (MSR_TM_ACTIVE(target->thread.regs->msr))
+ target->thread.transact_vrsave = vrsave.word;
+ else
+ target->thread.vrsave = vrsave.word;
+ }
}
-
return ret;
}
#endif /* CONFIG_ALTIVEC */
@@ -613,6 +711,347 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
}
#endif /* CONFIG_SPE */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+
+/*
+ * Transactional memory SPR
+ *
+ * struct {
+ * u64 tm_tfhar;
+ * u64 tm_texasr;
+ * u64 tm_tfiar;
+ * unsigned long tm_orig_msr;
+ * unsigned long tm_tar;
+ * unsigned long tm_ppr;
+ * unsigned long tm_dscr;
+ * };
+ */
+static int tm_spr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+
+ /* TFHAR register */
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tfhar, 0, sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar) +
+ sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
+
+ /* TEXASR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr) +
+ sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
+
+ /* TFIAR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar) +
+ sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
+
+ /* TM checkpointed original MSR */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_orig_msr, 3 * sizeof(u64),
+ 3 * sizeof(u64) + sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr) +
+ sizeof(unsigned long) + sizeof(struct pt_regs)
+ != offsetof(struct thread_struct, tm_tar));
+
+ /* TM checkpointed TAR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tar, 3 * sizeof(u64) +
+ sizeof(unsigned long) , 3 * sizeof(u64) +
+ 2 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
+ + sizeof(unsigned long) !=
+ offsetof(struct thread_struct, tm_ppr));
+
+ /* TM checkpointed PPR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_ppr, 3 * sizeof(u64) +
+ 2 * sizeof(unsigned long), 3 * sizeof(u64) +
+ 3 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
+ sizeof(unsigned long) !=
+ offsetof(struct thread_struct, tm_dscr));
+
+ /* TM checkpointed DSCR register */
+ if (!ret)
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_dscr, 3 * sizeof(u64)
+ + 3 * sizeof(unsigned long), 3 * sizeof(u64)
+ + 4 * sizeof(unsigned long));
+ return ret;
+}
+
+static int tm_spr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+
+ /* TFHAR register */
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tfhar, 0, sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfhar)
+ + sizeof(u64) != offsetof(struct thread_struct, tm_texasr));
+
+ /* TEXASR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_texasr, sizeof(u64), 2 * sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_texasr)
+ + sizeof(u64) != offsetof(struct thread_struct, tm_tfiar));
+
+ /* TFIAR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tfiar, 2 * sizeof(u64), 3 * sizeof(u64));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tfiar)
+ + sizeof(u64) != offsetof(struct thread_struct, tm_orig_msr));
+
+ /* TM checkpointed orig MSR */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_orig_msr, 3 * sizeof(u64),
+ 3 * sizeof(u64) + sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_orig_msr)
+ + sizeof(unsigned long) + sizeof(struct pt_regs) !=
+ offsetof(struct thread_struct, tm_tar));
+
+ /* TM checkpointed TAR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_tar, 3 * sizeof(u64) +
+ sizeof(unsigned long), 3 * sizeof(u64) +
+ 2 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_tar)
+ + sizeof(unsigned long) != offsetof(struct thread_struct, tm_ppr));
+
+ /* TM checkpointed PPR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_ppr, 3 * sizeof(u64)
+ + 2 * sizeof(unsigned long), 3 * sizeof(u64)
+ + 3 * sizeof(unsigned long));
+
+ BUILD_BUG_ON(offsetof(struct thread_struct, tm_ppr) +
+ sizeof(unsigned long) !=
+ offsetof(struct thread_struct, tm_dscr));
+
+ /* TM checkpointed DSCR register */
+ if (!ret)
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.tm_dscr,
+ 3 * sizeof(u64) + 3 * sizeof(unsigned long),
+ 3 * sizeof(u64) + 4 * sizeof(unsigned long));
+
+ return ret;
+}
+
+/*
+ * TM Checkpointed GPR
+ *
+ * struct data {
+ * struct pt_regs ckpt_regs;
+ * };
+ */
+static int tm_cgpr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.ckpt_regs, 0,
+ sizeof(struct pt_regs));
+ return ret;
+}
+
+static int tm_cgpr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.ckpt_regs, 0,
+ sizeof(struct pt_regs));
+ return ret;
+}
+
+/*
+ * TM Checkpointed FPR
+ *
+ * struct data {
+ * u64 fpr[32];
+ * u64 fpscr;
+ * };
+ */
+static int tm_cfpr_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+#ifdef CONFIG_VSX
+ u64 buf[33];
+ int i;
+#endif
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+
+#ifdef CONFIG_VSX
+ /* copy to local buffer then write that out */
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.TS_FPR(i);
+ buf[32] = target->thread.fp_state.fpscr;
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+
+#else
+ BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+ offsetof(struct thread_fp_state, fpr[32][0]));
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.thread_fp_state, 0, -1);
+#endif
+}
+
+static int tm_cfpr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+#ifdef CONFIG_VSX
+ u64 buf[33];
+ int i;
+#endif
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+
+#ifdef CONFIG_VSX
+ /* copy to local buffer then write that out */
+ i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+ if (i)
+ return i;
+ for (i = 0; i < 32 ; i++)
+ target->thread.TS_FPR(i) = buf[i];
+ target->thread.fp_state.fpscr = buf[32];
+ return 0;
+#else
+ BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
+ offsetof(struct thread_fp_state, fpr[32][0]));
+
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fp_state, 0, -1);
+#endif
+}
+
+/*
+ * TM Checkpointed VMX
+ *
+ * struct data {
+ * vector128 vr[32];
+ * vector128 vscr;
+ * vector128 vrsave;
+ *};
+ */
+static int tm_cvmx_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+
+ BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+ offsetof(struct thread_vr_state, vr[32]));
+
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.vr_state, 0,
+ 33 * sizeof(vector128));
+ if (!ret) {
+ /*
+ * Copy out only the low-order word of vrsave.
+ */
+ union {
+ elf_vrreg_t reg;
+ u32 word;
+ } vrsave;
+ memset(&vrsave, 0, sizeof(vrsave));
+ vrsave.word = target->thread.vrsave;
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
+ 33 * sizeof(vector128), -1);
+ }
+ return ret;
+}
+
+static int tm_cvmx_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+
+ flush_fp_to_thread(target);
+ flush_altivec_to_thread(target);
+ flush_tmreg_to_thread(target);
+
+ BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
+ offsetof(struct thread_vr_state, vr[32]));
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.vr_state, 0,
+ 33 * sizeof(vector128));
+ if (!ret && count > 0) {
+ /*
+ * We use only the first word of vrsave.
+ */
+ union {
+ elf_vrreg_t reg;
+ u32 word;
+ } vrsave;
+ memset(&vrsave, 0, sizeof(vrsave));
+ vrsave.word = target->thread.vrsave;
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
+ 33 * sizeof(vector128), -1);
+ if (!ret)
+ target->thread.vrsave = vrsave.word;
+ }
+ return ret;
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
/*
* These are our native regset flavors.
@@ -629,6 +1068,12 @@ enum powerpc_regset {
#ifdef CONFIG_SPE
REGSET_SPE,
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ REGSET_TM_SPR, /* TM specific SPR */
+ REGSET_TM_CGPR, /* TM checkpointed GPR */
+ REGSET_TM_CFPR, /* TM checkpointed FPR */
+ REGSET_TM_CVMX /* TM checkpointed VMX */
+#endif
};
static const struct user_regset native_regsets[] = {
@@ -663,6 +1108,28 @@ static const struct user_regset native_regsets[] = {
.active = evr_active, .get = evr_get, .set = evr_set
},
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ [REGSET_TM_SPR] = {
+ .core_note_type = NT_PPC_TM_SPR, .n = 7,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = tm_spr_get, .set = tm_spr_set
+ },
+ [REGSET_TM_CGPR] = {
+ .core_note_type = NT_PPC_TM_CGPR, .n = 14,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = tm_cgpr_get, .set = tm_cgpr_set
+ },
+ [REGSET_TM_CFPR] = {
+ .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
+ .size = sizeof(double), .align = sizeof(double),
+ .get = tm_cfpr_get, .set = tm_cfpr_set
+ },
+ [REGSET_TM_CVMX] = {
+ .core_note_type = NT_PPC_TM_CVMX, .n = 34,
+ .size = sizeof(vector128), .align = sizeof(vector128),
+ .get = tm_cvmx_get, .set = tm_cvmx_set
+ },
+#endif
};
static const struct user_regset_view user_ppc_native_view = {
@@ -831,6 +1298,28 @@ static const struct user_regset compat_regsets[] = {
.active = evr_active, .get = evr_get, .set = evr_set
},
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ [REGSET_TM_SPR] = {
+ .core_note_type = NT_PPC_TM_SPR, .n = 7,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = tm_spr_get, .set = tm_spr_set
+ },
+ [REGSET_TM_CGPR] = {
+ .core_note_type = NT_PPC_TM_CGPR, .n = 14,
+ .size = sizeof(u64), .align = sizeof(u64),
+ .get = tm_cgpr_get, .set = tm_cgpr_set
+ },
+ [REGSET_TM_CFPR] = {
+ .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
+ .size = sizeof(double), .align = sizeof(double),
+ .get = tm_cfpr_get, .set = tm_cfpr_set
+ },
+ [REGSET_TM_CVMX] = {
+ .core_note_type = NT_PPC_TM_CVMX, .n = 34,
+ .size = sizeof(vector128), .align = sizeof(vector128),
+ .get = tm_cvmx_get, .set = tm_cvmx_set
+ },
+#endif
};
static const struct user_regset_view user_ppc_compat_view = {
@@ -1754,7 +2243,32 @@ long arch_ptrace(struct task_struct *child, long request,
REGSET_SPE, 0, 35 * sizeof(u32),
datavp);
#endif
-
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ case PTRACE_GETTM_SPRREGS:
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_TM_SPR, 0, 6 * sizeof(u64) + sizeof(unsigned long), datavp);
+ case PTRACE_SETTM_SPRREGS:
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_TM_SPR, 0, 6 * sizeof(u64) + sizeof(unsigned long), datavp);
+ case PTRACE_GETTM_CGPRREGS:
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_TM_CGPR, 0, sizeof(struct pt_regs), datavp);
+ case PTRACE_SETTM_CGPRREGS:
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_TM_CGPR, 0, sizeof(struct pt_regs), datavp);
+ case PTRACE_GETTM_CFPRREGS:
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_TM_CFPR, 0, sizeof(elf_fpregset_t), datavp);
+ case PTRACE_SETTM_CFPRREGS:
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_TM_CFPR, 0, sizeof(elf_fpregset_t), datavp);
+ case PTRACE_GETTM_CVMXREGS:
+ return copy_regset_to_user(child, &user_ppc_native_view,
+ REGSET_TM_CVMX, 0, (33 * sizeof(vector128) + sizeof(u32)), datavp);
+ case PTRACE_SETTM_CVMXREGS:
+ return copy_regset_from_user(child, &user_ppc_native_view,
+ REGSET_TM_CVMX, 0, (33 * sizeof(vector128) + sizeof(u32)), datavp);
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
default:
ret = ptrace_request(child, request, addr, data);
break;
--
1.7.11.7
^ permalink raw reply related
* Re: [alsa-devel] [PATCH 0/2] Add ipg clock control to sai driver
From: Nicolin Chen @ 2014-04-02 8:01 UTC (permalink / raw)
To: Nicolin Chen
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
Li.Xiubo, ijc+devicetree, linux-kernel, robh+dt, Timur Tabi,
broonie, rob, galak, Shawn Guo, linuxppc-dev
In-Reply-To: <cover.1396352401.git.Guangyu.Chen@freescale.com>
[-- Attachment #1: Type: text/plain, Size: 1164 bytes --]
Please disregard this version.
SAI actually has three master clocks and one bus clock.
So the patch should have added three sai_clks to the driver.
I'll later send v2 to append the other two.
Thank you.
On Tue, Apr 1, 2014 at 7:52 PM, Nicolin Chen <Guangyu.Chen@freescale.com>wrote:
> This series of patches add ipg clock control to fsl_sai driver and updates
> the vf610.dtsi accordingly.
>
> @Shawn
> I'm not sure if VF610 currently does full works with SAI audio function.
> The PATCH-2 is based on broonie/for-next.
>
> Nicolin Chen (2):
> ASoC: fsl_sai: Add clock control for SAI
> ARM: dts: Add ipg clock for sai2 on VF610 platform
>
> .../devicetree/bindings/sound/fsl-sai.txt | 7 ++--
> arch/arm/boot/dts/vf610.dtsi | 4 +--
> sound/soc/fsl/fsl_sai.c | 37
> ++++++++++++++++++++--
> sound/soc/fsl/fsl_sai.h | 2 ++
> 4 files changed, 43 insertions(+), 7 deletions(-)
>
> --
> 1.8.4
>
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
[-- Attachment #2: Type: text/html, Size: 1846 bytes --]
^ permalink raw reply
* Re: [PATCH 0/3] Add new ptrace request macros on PowerPC
From: Anshuman Khandual @ 2014-04-02 9:32 UTC (permalink / raw)
To: Anshuman Khandual; +Cc: mikey, avagin, oleg, linux-kernel, linuxppc-dev, roland
In-Reply-To: <1396422144-11032-1-git-send-email-khandual@linux.vnet.ibm.com>
On 04/02/2014 12:32 PM, Anshuman Khandual wrote:
> This patch series adds new ELF note sections which are used to
> create new ptrace request macros for various transactional memory and
> miscellaneous registers on PowerPC. Please find the test case exploiting
> the new ptrace request macros and it's results on a POWER8 system.
>
> RFC: https://lkml.org/lkml/2014/4/1/292
>
> ============================== Results ==============================
> -------TM specific SPR------
> TM TFHAR: 100009dc
> TM TEXASR: de000001ac000001
> TM TFIAR: c00000000003f386
> TM CH ORIG_MSR: 900000050000f032
> TM CH TAR: 6
> TM CH PPR: c000000000000
> TM CH DSCR: 1
> -------TM checkpointed GPR-----
> TM CH GPR[0]: 1000097c
> TM CH GPR[1]: 5
> TM CH GPR[2]: 6
> TM CH GPR[7]: 1
> TM CH NIP: 100009dc
> TM CH LINK: 1000097c
> TM CH CCR: 22000422
> -------TM running GPR-----
> TM RN GPR[0]: 1000097c
> TM RN GPR[1]: 7
> TM RN GPR[2]: 8
> TM RN GPR[7]: 5
> TM RN NIP: 100009fc
> TM RN LINK: 1000097c
> TM RN CCR: 2000422
> -------TM running FPR-----
> TM RN FPR[0]: 1002d3a3780
> TM RN FPR[1]: 7
> TM RN FPR[2]: 8
> TM RN FPSCR: 0
> -------TM checkpointed FPR-----
> TM CH FPR[0]: 1002d3a3780
> TM CH FPR[1]: 5
> TM CH FPR[2]: 6
> TM CH FPSCR: 0
> -------Running miscellaneous registers-------
TM RN DSCR: 0
There is a problem in here which I forgot to mention. The running DSCR value
comes from thread->dscr component of the target process. While we are inside the
transaction (which is the case here as we are stuck at "b ." instruction and
have not reached TEND) thread->dscr should have the running value of the DSCR
register at that point of time. Here we expect the DSCR value to be 5 instead
of 0 as shown in the output above. During the tests when I moved the "b ." after
TEND, the thread->dscr gets the value of 5 while all check pointed reg values are
thrown away. I believe there is some problem in the way thread->dscr context
is saved away inside the TM section. Will look into this problem further and
keep informed.
^ permalink raw reply
* Re: [PATCH] cpuidle: add freescale e500 family porcessors idle support
From: Daniel Lezcano @ 2014-04-02 9:36 UTC (permalink / raw)
To: Dongsheng Wang, scottwood
Cc: chenhui.zhao, linux-pm, rjw, jason.jin, linuxppc-dev
In-Reply-To: <1396341234-40515-1-git-send-email-dongsheng.wang@freescale.com>
On 04/01/2014 10:33 AM, Dongsheng Wang wrote:
> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>
> Add cpuidle support for e500 family, using cpuidle framework to
> manage various low power modes. The new implementation will remain
> compatible with original idle method.
>
> I have done test about power consumption and latency. Cpuidle framework
> will make CPU response time faster than original method, but power
> consumption is higher than original method.
>
> Power consumption:
> The original method, power consumption is 10.51202 (W).
> The cpuidle framework, power consumption is 10.5311 (W).
>
> Latency:
> The original method, avg latency is 6782 (us).
> The cpuidle framework, avg latency is 6482 (us).
>
> Initially, this supports PW10, PW20 and subsequent patches will support
> DOZE/NAP and PH10, PH20.
>
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
>
> diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
> index 5b6c03f..9301420 100644
> --- a/arch/powerpc/include/asm/machdep.h
> +++ b/arch/powerpc/include/asm/machdep.h
> @@ -294,6 +294,15 @@ extern void power7_idle(void);
> extern void ppc6xx_idle(void);
> extern void book3e_idle(void);
>
> +static inline void cpuidle_wait(void)
> +{
> +#ifdef CONFIG_PPC64
> + book3e_idle();
> +#else
> + e500_idle();
> +#endif
> +}
> +
> /*
> * ppc_md contains a copy of the machine description structure for the
> * current platform. machine_id contains the initial address where the
> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
> index 97e1dc9..edd193f 100644
> --- a/arch/powerpc/kernel/sysfs.c
> +++ b/arch/powerpc/kernel/sysfs.c
> @@ -190,6 +190,9 @@ static ssize_t show_pw20_wait_time(struct device *dev,
> return sprintf(buf, "%llu\n", time > 0 ? time : 0);
> }
>
> +#ifdef CONFIG_CPU_IDLE_E500
> +u32 cpuidle_entry_bit;
> +#endif
> static void set_pw20_wait_entry_bit(void *val)
> {
> u32 *value = val;
> @@ -204,7 +207,11 @@ static void set_pw20_wait_entry_bit(void *val)
> /* set count */
> pw20_idle |= ((MAX_BIT - *value) << PWRMGTCR0_PW20_ENT_SHIFT);
>
> +#ifdef CONFIG_CPU_IDLE_E500
> + cpuidle_entry_bit = *value;
> +#else
> mtspr(SPRN_PWRMGTCR0, pw20_idle);
> +#endif
> }
>
> static ssize_t store_pw20_wait_time(struct device *dev,
> diff --git a/drivers/cpuidle/Kconfig.powerpc b/drivers/cpuidle/Kconfig.powerpc
> index 66c3a09..0949dbf 100644
> --- a/drivers/cpuidle/Kconfig.powerpc
> +++ b/drivers/cpuidle/Kconfig.powerpc
> @@ -18,3 +18,10 @@ config POWERNV_CPUIDLE
> help
> Select this option to enable processor idle state management
> through cpuidle subsystem.
> +
> +config CPU_IDLE_E500
> + bool "CPU Idle Driver for E500 family processors"
> + depends on CPU_IDLE
> + depends on FSL_SOC_BOOKE
> + help
> + Select this to enable cpuidle on e500 family processors.
> diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
> index f71ae1b..7e6adea 100644
> --- a/drivers/cpuidle/Makefile
> +++ b/drivers/cpuidle/Makefile
> @@ -18,3 +18,4 @@ obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o
> # POWERPC drivers
> obj-$(CONFIG_PSERIES_CPUIDLE) += cpuidle-pseries.o
> obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o
> +obj-$(CONFIG_CPU_IDLE_E500) += cpuidle-e500.o
> diff --git a/drivers/cpuidle/cpuidle-e500.c b/drivers/cpuidle/cpuidle-e500.c
> new file mode 100644
> index 0000000..ddc0def
> --- /dev/null
> +++ b/drivers/cpuidle/cpuidle-e500.c
> @@ -0,0 +1,194 @@
> +/*
> + * CPU Idle driver for Freescale PowerPC e500 family processors.
> + *
> + * Copyright 2014 Freescale Semiconductor, Inc.
> + *
> + * Author: Dongsheng Wang <dongsheng.wang@freescale.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/cpu.h>
> +#include <linux/cpuidle.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/notifier.h>
> +
> +#include <asm/cputable.h>
> +#include <asm/machdep.h>
> +#include <asm/mpc85xx.h>
> +
> +static unsigned int max_idle_state;
> +static struct cpuidle_state *cpuidle_state_table;
> +
> +struct cpuidle_driver e500_idle_driver = {
> + .name = "e500_idle",
> + .owner = THIS_MODULE,
> +};
> +
> +static void e500_cpuidle(void)
> +{
> + if (cpuidle_idle_call())
> + cpuidle_wait();
> +}
Nope, that has been changed. No more call to cpuidle_idle_call in a driver.
> +
> +static int pw10_enter(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv, int index)
> +{
> + cpuidle_wait();
> + return index;
> +}
> +
> +#define MAX_BIT 63
> +#define MIN_BIT 1
> +extern u32 cpuidle_entry_bit;
> +static int pw20_enter(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv, int index)
> +{
> + u32 pw20_idle;
> + u32 entry_bit;
> + pw20_idle = mfspr(SPRN_PWRMGTCR0);
> + if ((pw20_idle & PWRMGTCR0_PW20_ENT) != PWRMGTCR0_PW20_ENT) {
> + pw20_idle &= ~PWRMGTCR0_PW20_ENT;
> + entry_bit = MAX_BIT - cpuidle_entry_bit;
> + pw20_idle |= (entry_bit << PWRMGTCR0_PW20_ENT_SHIFT);
> + mtspr(SPRN_PWRMGTCR0, pw20_idle);
> + }
> +
> + cpuidle_wait();
> +
> + pw20_idle &= ~PWRMGTCR0_PW20_ENT;
> + pw20_idle |= (MIN_BIT << PWRMGTCR0_PW20_ENT_SHIFT);
> + mtspr(SPRN_PWRMGTCR0, pw20_idle);
> +
> + return index;
> +}
Is it possible to give some comments and encapsulate the code with
explicit function names to be implemented in an arch specific directory
file (eg. pm.c) and export these functions in a linux/ header ? We try
to prevent to include asm if possible.
> +
> +static struct cpuidle_state pw_idle_states[] = {
> + {
> + .name = "pw10",
> + .desc = "pw10",
> + .flags = CPUIDLE_FLAG_TIME_VALID,
> + .exit_latency = 0,
> + .target_residency = 0,
> + .enter = &pw10_enter
> + },
> +
> + {
> + .name = "pw20",
> + .desc = "pw20-core-idle",
> + .flags = CPUIDLE_FLAG_TIME_VALID,
> + .exit_latency = 1,
> + .target_residency = 50,
> + .enter = &pw20_enter
> + },
> +};
No need to define this intermediate structure here, you can directly
initialize the cpuidle_driver:
struct cpuidle_driver e500_idle_driver = {
.name = "e500_idle",
.owner = THIS_MODULE,
.states = {
.name = "pw10",
.desc = "pw10",
.flags = CPUIDLE_FLAG_TIME_VALID,
.target_residency = 0,
.enter = &pw10_enter,
},
....
.state_count = 2,
};
Then in the init function you initialize the state_count consequently:
if (PVR_VER(cur_cpu_spec->pvr_value) != PVR_VER_E6500)
drv->state_count = 1;
Then you can kill:
max_idle_state, cpuidle_state_table, e500_idle_state_probe and
pw_idle_states.
> +
> +static int cpu_hotplug_notify(struct notifier_block *n,
> + unsigned long action, void *hcpu)
> +{
> + unsigned long hotcpu = (unsigned long)hcpu;
> + struct cpuidle_device *dev =
> + per_cpu_ptr(cpuidle_devices, hotcpu);
> +
> + if (dev && cpuidle_get_driver()) {
> + switch (action) {
> + case CPU_ONLINE:
> + case CPU_ONLINE_FROZEN:
> + cpuidle_pause_and_lock();
> + cpuidle_enable_device(dev);
> + cpuidle_resume_and_unlock();
> + break;
> +
> + case CPU_DEAD:
> + case CPU_DEAD_FROZEN:
> + cpuidle_pause_and_lock();
> + cpuidle_disable_device(dev);
> + cpuidle_resume_and_unlock();
> + break;
> +
> + default:
> + return NOTIFY_DONE;
> + }
> + }
> +
> + return NOTIFY_OK;
> +}
> +
> +static struct notifier_block cpu_hotplug_notifier = {
> + .notifier_call = cpu_hotplug_notify,
> +};
Can you explain why this is needed ?
> +static void e500_cpuidle_driver_init(void)
> +{
> + int idle_state;
> + struct cpuidle_driver *drv = &e500_idle_driver;
Pass the cpuidle_driver as parameter to the function.
> +
> + drv->state_count = 0;
> +
> + for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
> + if (!cpuidle_state_table[idle_state].enter)
> + break;
> +
> + drv->states[drv->state_count] = cpuidle_state_table[idle_state];
> + drv->state_count++;
> + }
This code should disappear.
As this function will just initialize state_count, you can move it in
caller and kill this function.
> +}
> +
> +static int e500_idle_state_probe(void)
> +{
> + if (cpuidle_disable != IDLE_NO_OVERRIDE)
> + return -ENODEV;
> +
> + cpuidle_state_table = pw_idle_states;
> + max_idle_state = ARRAY_SIZE(pw_idle_states);
> +
> + /* Disable PW20 feature for e500mc, e5500 */
> + if (PVR_VER(cur_cpu_spec->pvr_value) != PVR_VER_E6500)
> + cpuidle_state_table[1].enter = NULL;
> +
> + if (!cpuidle_state_table || !max_idle_state)
> + return -ENODEV;
> +
> + return 0;
> +}
This code should disappear.
> +static void replace_orig_idle(void *dummy)
> +{
> + return;
> +}
> +
> +static int __init e500_idle_init(void)
> +{
> + struct cpuidle_driver *drv = &e500_idle_driver;
> + int err;
> +
> + if (e500_idle_state_probe())
> + return -ENODEV;
> +
> + e500_cpuidle_driver_init();
> + if (!drv->state_count)
> + return -ENODEV;
No need of this check, because:
1. you know how you initialized the driver (1 or 2 states)
2. this is already by the cpuidle framework
> +
> + err = cpuidle_register(drv, NULL);
> + if (err) {
> + pr_err("Register e500 family cpuidle driver failed.\n");
extra carriage return.
> +
> + return err;
> + }
> +
> + err = register_cpu_notifier(&cpu_hotplug_notifier);
> + if (err)
> + pr_warn("Cpuidle driver: register cpu notifier failed.\n");
> +
> + /* Replace the original way of idle after cpuidle registered. */
> + ppc_md.power_save = e500_cpuidle;
> + on_each_cpu(replace_orig_idle, NULL, 1);
Why ?
> + pr_info("e500_idle_driver registered.\n");
> +
> + return 0;
> +}
> +late_initcall(e500_idle_init);
>
Thanks
-- Daniel
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [PATCH] cpuidle: add freescale e500 family porcessors idle support
From: Daniel Lezcano @ 2014-04-02 9:39 UTC (permalink / raw)
To: Dongsheng Wang, scottwood
Cc: chenhui.zhao, linux-pm, Rafael J. Wysocki, jason.jin,
linuxppc-dev
In-Reply-To: <533BDA11.9080905@linaro.org>
On 04/02/2014 11:36 AM, Daniel Lezcano wrote:
> On 04/01/2014 10:33 AM, Dongsheng Wang wrote:
>> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>>
>> Add cpuidle support for e500 family, using cpuidle framework to
>> manage various low power modes. The new implementation will remain
>> compatible with original idle method.
>>
>> I have done test about power consumption and latency. Cpuidle framework
>> will make CPU response time faster than original method, but power
>> consumption is higher than original method.
>>
>> Power consumption:
>> The original method, power consumption is 10.51202 (W).
>> The cpuidle framework, power consumption is 10.5311 (W).
>>
>> Latency:
>> The original method, avg latency is 6782 (us).
>> The cpuidle framework, avg latency is 6482 (us).
>>
>> Initially, this supports PW10, PW20 and subsequent patches will support
>> DOZE/NAP and PH10, PH20.
>>
>> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Please fix Rafael's email when resending/answering.
Thanks
-- Daniel
>> diff --git a/arch/powerpc/include/asm/machdep.h
>> b/arch/powerpc/include/asm/machdep.h
>> index 5b6c03f..9301420 100644
>> --- a/arch/powerpc/include/asm/machdep.h
>> +++ b/arch/powerpc/include/asm/machdep.h
>> @@ -294,6 +294,15 @@ extern void power7_idle(void);
>> extern void ppc6xx_idle(void);
>> extern void book3e_idle(void);
>>
>> +static inline void cpuidle_wait(void)
>> +{
>> +#ifdef CONFIG_PPC64
>> + book3e_idle();
>> +#else
>> + e500_idle();
>> +#endif
>> +}
>> +
>> /*
>> * ppc_md contains a copy of the machine description structure for the
>> * current platform. machine_id contains the initial address where the
>> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
>> index 97e1dc9..edd193f 100644
>> --- a/arch/powerpc/kernel/sysfs.c
>> +++ b/arch/powerpc/kernel/sysfs.c
>> @@ -190,6 +190,9 @@ static ssize_t show_pw20_wait_time(struct device
>> *dev,
>> return sprintf(buf, "%llu\n", time > 0 ? time : 0);
>> }
>>
>> +#ifdef CONFIG_CPU_IDLE_E500
>> +u32 cpuidle_entry_bit;
>> +#endif
>> static void set_pw20_wait_entry_bit(void *val)
>> {
>> u32 *value = val;
>> @@ -204,7 +207,11 @@ static void set_pw20_wait_entry_bit(void *val)
>> /* set count */
>> pw20_idle |= ((MAX_BIT - *value) << PWRMGTCR0_PW20_ENT_SHIFT);
>>
>> +#ifdef CONFIG_CPU_IDLE_E500
>> + cpuidle_entry_bit = *value;
>> +#else
>> mtspr(SPRN_PWRMGTCR0, pw20_idle);
>> +#endif
>> }
>>
>> static ssize_t store_pw20_wait_time(struct device *dev,
>> diff --git a/drivers/cpuidle/Kconfig.powerpc
>> b/drivers/cpuidle/Kconfig.powerpc
>> index 66c3a09..0949dbf 100644
>> --- a/drivers/cpuidle/Kconfig.powerpc
>> +++ b/drivers/cpuidle/Kconfig.powerpc
>> @@ -18,3 +18,10 @@ config POWERNV_CPUIDLE
>> help
>> Select this option to enable processor idle state management
>> through cpuidle subsystem.
>> +
>> +config CPU_IDLE_E500
>> + bool "CPU Idle Driver for E500 family processors"
>> + depends on CPU_IDLE
>> + depends on FSL_SOC_BOOKE
>> + help
>> + Select this to enable cpuidle on e500 family processors.
>> diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
>> index f71ae1b..7e6adea 100644
>> --- a/drivers/cpuidle/Makefile
>> +++ b/drivers/cpuidle/Makefile
>> @@ -18,3 +18,4 @@ obj-$(CONFIG_ARM_AT91_CPUIDLE) +=
>> cpuidle-at91.o
>> # POWERPC drivers
>> obj-$(CONFIG_PSERIES_CPUIDLE) += cpuidle-pseries.o
>> obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o
>> +obj-$(CONFIG_CPU_IDLE_E500) += cpuidle-e500.o
>> diff --git a/drivers/cpuidle/cpuidle-e500.c
>> b/drivers/cpuidle/cpuidle-e500.c
>> new file mode 100644
>> index 0000000..ddc0def
>> --- /dev/null
>> +++ b/drivers/cpuidle/cpuidle-e500.c
>> @@ -0,0 +1,194 @@
>> +/*
>> + * CPU Idle driver for Freescale PowerPC e500 family processors.
>> + *
>> + * Copyright 2014 Freescale Semiconductor, Inc.
>> + *
>> + * Author: Dongsheng Wang <dongsheng.wang@freescale.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/cpu.h>
>> +#include <linux/cpuidle.h>
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/notifier.h>
>> +
>> +#include <asm/cputable.h>
>> +#include <asm/machdep.h>
>> +#include <asm/mpc85xx.h>
>> +
>> +static unsigned int max_idle_state;
>> +static struct cpuidle_state *cpuidle_state_table;
>> +
>> +struct cpuidle_driver e500_idle_driver = {
>> + .name = "e500_idle",
>> + .owner = THIS_MODULE,
>> +};
>> +
>> +static void e500_cpuidle(void)
>> +{
>> + if (cpuidle_idle_call())
>> + cpuidle_wait();
>> +}
>
> Nope, that has been changed. No more call to cpuidle_idle_call in a driver.
>
>> +
>> +static int pw10_enter(struct cpuidle_device *dev,
>> + struct cpuidle_driver *drv, int index)
>> +{
>> + cpuidle_wait();
>> + return index;
>> +}
>> +
>> +#define MAX_BIT 63
>> +#define MIN_BIT 1
>> +extern u32 cpuidle_entry_bit;
>> +static int pw20_enter(struct cpuidle_device *dev,
>> + struct cpuidle_driver *drv, int index)
>> +{
>> + u32 pw20_idle;
>> + u32 entry_bit;
>> + pw20_idle = mfspr(SPRN_PWRMGTCR0);
>> + if ((pw20_idle & PWRMGTCR0_PW20_ENT) != PWRMGTCR0_PW20_ENT) {
>> + pw20_idle &= ~PWRMGTCR0_PW20_ENT;
>> + entry_bit = MAX_BIT - cpuidle_entry_bit;
>> + pw20_idle |= (entry_bit << PWRMGTCR0_PW20_ENT_SHIFT);
>> + mtspr(SPRN_PWRMGTCR0, pw20_idle);
>> + }
>> +
>> + cpuidle_wait();
>> +
>> + pw20_idle &= ~PWRMGTCR0_PW20_ENT;
>> + pw20_idle |= (MIN_BIT << PWRMGTCR0_PW20_ENT_SHIFT);
>> + mtspr(SPRN_PWRMGTCR0, pw20_idle);
>> +
>> + return index;
>> +}
>
> Is it possible to give some comments and encapsulate the code with
> explicit function names to be implemented in an arch specific directory
> file (eg. pm.c) and export these functions in a linux/ header ? We try
> to prevent to include asm if possible.
>
>> +
>> +static struct cpuidle_state pw_idle_states[] = {
>> + {
>> + .name = "pw10",
>> + .desc = "pw10",
>> + .flags = CPUIDLE_FLAG_TIME_VALID,
>> + .exit_latency = 0,
>> + .target_residency = 0,
>> + .enter = &pw10_enter
>> + },
>> +
>> + {
>> + .name = "pw20",
>> + .desc = "pw20-core-idle",
>> + .flags = CPUIDLE_FLAG_TIME_VALID,
>> + .exit_latency = 1,
>> + .target_residency = 50,
>> + .enter = &pw20_enter
>> + },
>> +};
>
> No need to define this intermediate structure here, you can directly
> initialize the cpuidle_driver:
>
>
> struct cpuidle_driver e500_idle_driver = {
> .name = "e500_idle",
> .owner = THIS_MODULE,
> .states = {
> .name = "pw10",
> .desc = "pw10",
> .flags = CPUIDLE_FLAG_TIME_VALID,
> .target_residency = 0,
> .enter = &pw10_enter,
> },
>
> ....
>
> .state_count = 2,
> };
>
> Then in the init function you initialize the state_count consequently:
>
> if (PVR_VER(cur_cpu_spec->pvr_value) != PVR_VER_E6500)
> drv->state_count = 1;
>
> Then you can kill:
>
> max_idle_state, cpuidle_state_table, e500_idle_state_probe and
> pw_idle_states.
>
>> +
>> +static int cpu_hotplug_notify(struct notifier_block *n,
>> + unsigned long action, void *hcpu)
>> +{
>> + unsigned long hotcpu = (unsigned long)hcpu;
>> + struct cpuidle_device *dev =
>> + per_cpu_ptr(cpuidle_devices, hotcpu);
>> +
>> + if (dev && cpuidle_get_driver()) {
>> + switch (action) {
>> + case CPU_ONLINE:
>> + case CPU_ONLINE_FROZEN:
>> + cpuidle_pause_and_lock();
>> + cpuidle_enable_device(dev);
>> + cpuidle_resume_and_unlock();
>> + break;
>> +
>> + case CPU_DEAD:
>> + case CPU_DEAD_FROZEN:
>> + cpuidle_pause_and_lock();
>> + cpuidle_disable_device(dev);
>> + cpuidle_resume_and_unlock();
>> + break;
>> +
>> + default:
>> + return NOTIFY_DONE;
>> + }
>> + }
>> +
>> + return NOTIFY_OK;
>> +}
>> +
>> +static struct notifier_block cpu_hotplug_notifier = {
>> + .notifier_call = cpu_hotplug_notify,
>> +};
>
> Can you explain why this is needed ?
>
>> +static void e500_cpuidle_driver_init(void)
>> +{
>> + int idle_state;
>> + struct cpuidle_driver *drv = &e500_idle_driver;
>
> Pass the cpuidle_driver as parameter to the function.
>
>> +
>> + drv->state_count = 0;
>> +
>> + for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
>> + if (!cpuidle_state_table[idle_state].enter)
>> + break;
>> +
>> + drv->states[drv->state_count] = cpuidle_state_table[idle_state];
>> + drv->state_count++;
>> + }
>
> This code should disappear.
>
> As this function will just initialize state_count, you can move it in
> caller and kill this function.
>
>> +}
>> +
>> +static int e500_idle_state_probe(void)
>> +{
>> + if (cpuidle_disable != IDLE_NO_OVERRIDE)
>> + return -ENODEV;
>> +
>> + cpuidle_state_table = pw_idle_states;
>> + max_idle_state = ARRAY_SIZE(pw_idle_states);
>> +
>> + /* Disable PW20 feature for e500mc, e5500 */
>> + if (PVR_VER(cur_cpu_spec->pvr_value) != PVR_VER_E6500)
>> + cpuidle_state_table[1].enter = NULL;
>> +
>> + if (!cpuidle_state_table || !max_idle_state)
>> + return -ENODEV;
>> +
>> + return 0;
>> +}
>
> This code should disappear.
>
>> +static void replace_orig_idle(void *dummy)
>> +{
>> + return;
>> +}
>> +
>> +static int __init e500_idle_init(void)
>> +{
>> + struct cpuidle_driver *drv = &e500_idle_driver;
>> + int err;
>> +
>> + if (e500_idle_state_probe())
>> + return -ENODEV;
>> +
>> + e500_cpuidle_driver_init();
>> + if (!drv->state_count)
>> + return -ENODEV;
>
> No need of this check, because:
>
> 1. you know how you initialized the driver (1 or 2 states)
> 2. this is already by the cpuidle framework
>
>> +
>> + err = cpuidle_register(drv, NULL);
>> + if (err) {
>> + pr_err("Register e500 family cpuidle driver failed.\n");
>
> extra carriage return.
>> +
>> + return err;
>> + }
>> +
>> + err = register_cpu_notifier(&cpu_hotplug_notifier);
>> + if (err)
>> + pr_warn("Cpuidle driver: register cpu notifier failed.\n");
>> +
>> + /* Replace the original way of idle after cpuidle registered. */
>> + ppc_md.power_save = e500_cpuidle;
>> + on_each_cpu(replace_orig_idle, NULL, 1);
>
> Why ?
>
>> + pr_info("e500_idle_driver registered.\n");
>> +
>> + return 0;
>> +}
>> +late_initcall(e500_idle_init);
>>
>
> Thanks
>
> -- Daniel
>
>
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [PATCH] gpio: ge: Convert to platform driver
From: Alexandre Courbot @ 2014-04-02 9:41 UTC (permalink / raw)
To: Alexander Shiyan; +Cc: linux-gpio@vger.kernel.org, Linus Walleij, linuxppc-dev
In-Reply-To: <1396156455-4225-1-git-send-email-shc_work@mail.ru>
On Sun, Mar 30, 2014 at 2:14 PM, Alexander Shiyan <shc_work@mail.ru> wrote:
> This patch converts GE I/O FPGA GPIO driver to platform driver.
>
> Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
> ---
> Only compile tested.
Could we get a couple of Tested-by by people who can try this patch?
It greatly simplifies the driver, but we need to make sure it doesn't
break anything before going further...
^ permalink raw reply
* [PATCH v2 0/2] ASoC: fsl_sai: Add bus clock and mclks with clock controls
From: Nicolin Chen @ 2014-04-02 10:10 UTC (permalink / raw)
To: broonie, shawn.guo
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
ijc+devicetree, linux-kernel, robh+dt, timur, Li.Xiubo, rob,
galak, linuxppc-dev
This series of patches add clock controls to fsl_sai driver and updates
the vf610.dtsi accordingly.
Changelog
v2:
* Appended two extra mclks to the driver since SAI actually has three.
* Renamed clock name to 'bus' and 'mclk' according to the reference manual.
Nicolin Chen (2):
ASoC: fsl_sai: Add clock controls for SAI
ARM: dts: Append clock bindings for sai2 on VF610 platform
.../devicetree/bindings/sound/fsl-sai.txt | 8 ++--
arch/arm/boot/dts/vf610.dtsi | 6 ++-
sound/soc/fsl/fsl_sai.c | 50 ++++++++++++++++++++--
sound/soc/fsl/fsl_sai.h | 4 ++
4 files changed, 59 insertions(+), 9 deletions(-)
--
1.8.4
^ permalink raw reply
* [PATCH v2 1/2] ASoC: fsl_sai: Add clock controls for SAI
From: Nicolin Chen @ 2014-04-02 10:10 UTC (permalink / raw)
To: broonie, shawn.guo
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
ijc+devicetree, linux-kernel, robh+dt, timur, Li.Xiubo, rob,
galak, linuxppc-dev
In-Reply-To: <cover.1396432924.git.Guangyu.Chen@freescale.com>
The SAI mainly has the following clocks:
bus clock
control and configuration registers and to generate synchronous
interrupts and DMA requests.
mclk1, mclk2, mclk3
to generate the bit clock when the receiver or transmitter is
configured for an internally generated bit clock.
So this patch adds these clocks to the driver and their clock controls.
Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---
.../devicetree/bindings/sound/fsl-sai.txt | 8 ++--
sound/soc/fsl/fsl_sai.c | 50 ++++++++++++++++++++--
sound/soc/fsl/fsl_sai.h | 4 ++
3 files changed, 55 insertions(+), 7 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt
index 35c09fe..8a273bc 100644
--- a/Documentation/devicetree/bindings/sound/fsl-sai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt
@@ -10,7 +10,8 @@ Required properties:
- compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai".
- reg: Offset and length of the register set for the device.
- clocks: Must contain an entry for each entry in clock-names.
-- clock-names : Must include the "sai" entry.
+- clock-names : Must include the "bus" for register access and "mclk1" "mclk2"
+ "mclk3" for bit clock and frame clock providing.
- dmas : Generic dma devicetree binding as described in
Documentation/devicetree/bindings/dma/dma.txt.
- dma-names : Two dmas have to be defined, "tx" and "rx".
@@ -30,8 +31,9 @@ sai2: sai@40031000 {
reg = <0x40031000 0x1000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sai2_1>;
- clocks = <&clks VF610_CLK_SAI2>;
- clock-names = "sai";
+ clocks = <&clks VF610_CLK_SAI2>, <&clks VF610_CLK_SAI2>
+ <&clks 0>, <&clks 0>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3";
dma-names = "tx", "rx";
dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
<&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 9cd1764..99051c7 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -401,7 +401,22 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 reg;
+ struct device *dev = &sai->pdev->dev;
+ u32 reg, ret, i;
+
+ ret = clk_prepare_enable(sai->bus_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable bus clock\n");
+ return ret;
+ }
+
+ for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
+ ret = clk_prepare_enable(sai->mclk_clk[i]);
+ if (ret) {
+ dev_err(dev, "failed to enable mclk%d clock\n", i + 1);
+ goto err;
+ }
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg = FSL_SAI_TCR3;
@@ -412,13 +427,20 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
FSL_SAI_CR3_TRCE);
return 0;
+
+err:
+ for (; i > 0; i--)
+ clk_disable_unprepare(sai->mclk_clk[i - 1]);
+ clk_disable_unprepare(sai->bus_clk);
+
+ return ret;
}
static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 reg;
+ u32 reg, i;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg = FSL_SAI_TCR3;
@@ -427,6 +449,10 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
~FSL_SAI_CR3_TRCE);
+
+ for (i = 0; i < FSL_SAI_MCLK_MAX; i++)
+ clk_disable_unprepare(sai->mclk_clk[i]);
+ clk_disable_unprepare(sai->bus_clk);
}
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -559,7 +585,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
struct fsl_sai *sai;
struct resource *res;
void __iomem *base;
- int irq, ret;
+ char tmp[8];
+ int irq, ret, i;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
@@ -582,12 +609,27 @@ static int fsl_sai_probe(struct platform_device *pdev)
return PTR_ERR(base);
sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
- "sai", base, &fsl_sai_regmap_config);
+ "bus", base, &fsl_sai_regmap_config);
if (IS_ERR(sai->regmap)) {
dev_err(&pdev->dev, "regmap init failed\n");
return PTR_ERR(sai->regmap);
}
+ sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(sai->bus_clk)) {
+ dev_err(&pdev->dev, "failed to get bus clock\n");
+ return PTR_ERR(sai->bus_clk);
+ }
+
+ for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
+ sprintf(tmp, "mclk%d", i + 1);
+ sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
+ if (IS_ERR(sai->mclk_clk[i])) {
+ dev_err(&pdev->dev, "failed to get mclk%d clock\n", i + 1);
+ return PTR_ERR(sai->mclk_clk[i]);
+ }
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 677670d..0e6c9f5 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -119,6 +119,8 @@
#define FSL_SAI_CLK_MAST2 2
#define FSL_SAI_CLK_MAST3 3
+#define FSL_SAI_MCLK_MAX 3
+
/* SAI data transfer numbers per DMA request */
#define FSL_SAI_MAXBURST_TX 6
#define FSL_SAI_MAXBURST_RX 6
@@ -126,6 +128,8 @@
struct fsl_sai {
struct platform_device *pdev;
struct regmap *regmap;
+ struct clk *bus_clk;
+ struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
bool big_endian_regs;
bool big_endian_data;
--
1.8.4
^ permalink raw reply related
* [PATCH v2 2/2] ARM: dts: Append clock bindings for sai2 on VF610 platform
From: Nicolin Chen @ 2014-04-02 10:10 UTC (permalink / raw)
To: broonie, shawn.guo
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
ijc+devicetree, linux-kernel, robh+dt, timur, Li.Xiubo, rob,
galak, linuxppc-dev
In-Reply-To: <cover.1396432924.git.Guangyu.Chen@freescale.com>
Since we added fours clock to the DT binding, we should update the current
SAI dts/dtsi so as not to break their functions.
Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---
arch/arm/boot/dts/vf610.dtsi | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi
index d31ce1b..9fd0007 100644
--- a/arch/arm/boot/dts/vf610.dtsi
+++ b/arch/arm/boot/dts/vf610.dtsi
@@ -139,8 +139,10 @@
compatible = "fsl,vf610-sai";
reg = <0x40031000 0x1000>;
interrupts = <0 86 0x04>;
- clocks = <&clks VF610_CLK_SAI2>;
- clock-names = "sai";
+ clocks = <&clks VF610_CLK_SAI2>,
+ <&clks VF610_CLK_SAI2>,
+ <&clks 0>, <&clks 0>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3";
status = "disabled";
};
--
1.8.4
^ permalink raw reply related
* Re: [PATCH] gpio: ge: Convert to platform driver
From: Alexander Shiyan @ 2014-04-02 10:13 UTC (permalink / raw)
To: Alexandre Courbot; +Cc: linux-gpio@vger.kernel.org, Linus Walleij, linuxppc-dev
In-Reply-To: <CAAVeFu+8sjgtGGUv8O+FLy_3vbtQV+2m5rsJ9FccPoq6AiOFsg@mail.gmail.com>
V2VkLCAyIEFwciAyMDE0IDE4OjQxOjU1ICswOTAwINC+0YIgQWxleGFuZHJlIENvdXJib3QgPGdu
dXJvdUBnbWFpbC5jb20+Ogo+IE9uIFN1biwgTWFyIDMwLCAyMDE0IGF0IDI6MTQgUE0sIEFsZXhh
bmRlciBTaGl5YW4gPHNoY193b3JrQG1haWwucnU+IHdyb3RlOgo+ID4gVGhpcyBwYXRjaCBjb252
ZXJ0cyBHRSBJL08gRlBHQSBHUElPIGRyaXZlciB0byBwbGF0Zm9ybSBkcml2ZXIuCj4gPgo+ID4g
U2lnbmVkLW9mZi1ieTogQWxleGFuZGVyIFNoaXlhbiA8c2hjX3dvcmtAbWFpbC5ydT4KPiA+IC0t
LQo+ID4gT25seSBjb21waWxlIHRlc3RlZC4KPiAKPiBDb3VsZCB3ZSBnZXQgYSBjb3VwbGUgb2Yg
VGVzdGVkLWJ5IGJ5IHBlb3BsZSB3aG8gY2FuIHRyeSB0aGlzIHBhdGNoPwo+IEl0IGdyZWF0bHkg
c2ltcGxpZmllcyB0aGUgZHJpdmVyLCBidXQgd2UgbmVlZCB0byBtYWtlIHN1cmUgaXQgZG9lc24n
dAo+IGJyZWFrIGFueXRoaW5nIGJlZm9yZSBnb2luZyBmdXJ0aGVyLi4uCgpZZWFoLCBJJ20gd2Fp
dCBmb3IgdGhpcyB0b28uIEluIGFueSBjYXNlLCBJIHdhbnQgdG8gc3VibWl0IHYyIGEgYml0IGxh
dGVyLgoKLS0tCgo=
^ permalink raw reply
* Re: [PATCH REPOST v5 1/3] powernv, cpufreq: Select CPUFreq related Kconfig options for powernv
From: Rafael J. Wysocki @ 2014-04-02 11:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Gautham R. Shenoy, Linux PM list, Viresh Kumar, linux-kernel,
cpufreq, linuxppc-dev, Anton Blanchard, srivatsa.bhat
In-Reply-To: <1396412608.1394.15.camel@pasglop>
On Wednesday, April 02, 2014 03:23:28 PM Benjamin Herrenschmidt wrote:
> On Wed, 2014-04-02 at 00:03 +0200, Rafael J. Wysocki wrote:
> > > Rafael, are you going to take these or should I send them to Linus ?
> > >
> > > (I'd rather you take them :-)
> >
> > I can do that, but the timing is pretty bad. How urgent are they?
>
> To be honest pretty urgent. It's a new drop-in driver so it shouldn't
> be a huge deal.
>
> We have distros really waiting for this to hit upstream... But I'll
> leave that decision to you :-)
Well, I've already sent a second pull request for this merge window
and I'm not going to send the next one before it is merged.
So, I can push them next week realistically.
Rafael
^ permalink raw reply
* Re: [PATCH REPOST v5 1/3] powernv, cpufreq: Select CPUFreq related Kconfig options for powernv
From: Benjamin Herrenschmidt @ 2014-04-02 11:29 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Gautham R. Shenoy, Linux PM list, Viresh Kumar, linux-kernel,
cpufreq, linuxppc-dev, Anton Blanchard, srivatsa.bhat
In-Reply-To: <1621325.cz1O3Ng49e@vostro.rjw.lan>
On Wed, 2014-04-02 at 13:03 +0200, Rafael J. Wysocki wrote:
> > To be honest pretty urgent. It's a new drop-in driver so it
> shouldn't
> > be a huge deal.
> >
> > We have distros really waiting for this to hit upstream... But I'll
> > leave that decision to you :-)
>
> Well, I've already sent a second pull request for this merge window
> and I'm not going to send the next one before it is merged.
>
> So, I can push them next week realistically.
Thanks. You can blame me for the lateness if you want (and the debate as
to which tree should carry them :-)
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH v2 2/2] ARM: dts: Append clock bindings for sai2 on VF610 platform
From: Shawn Guo @ 2014-04-02 13:03 UTC (permalink / raw)
To: Nicolin Chen
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
broonie, ijc+devicetree, linux-kernel, robh+dt, timur, Li.Xiubo,
rob, galak, linuxppc-dev
In-Reply-To: <d09da3eb629143abd3f61ae037af4ddaf7286a83.1396432924.git.Guangyu.Chen@freescale.com>
On Wed, Apr 02, 2014 at 06:10:20PM +0800, Nicolin Chen wrote:
> Since we added fours clock to the DT binding, we should update the current
> SAI dts/dtsi so as not to break their functions.
>
> Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
> ---
> arch/arm/boot/dts/vf610.dtsi | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi
> index d31ce1b..9fd0007 100644
> --- a/arch/arm/boot/dts/vf610.dtsi
> +++ b/arch/arm/boot/dts/vf610.dtsi
> @@ -139,8 +139,10 @@
> compatible = "fsl,vf610-sai";
> reg = <0x40031000 0x1000>;
> interrupts = <0 86 0x04>;
> - clocks = <&clks VF610_CLK_SAI2>;
> - clock-names = "sai";
> + clocks = <&clks VF610_CLK_SAI2>,
> + <&clks VF610_CLK_SAI2>,
> + <&clks 0>, <&clks 0>;
So it seems that SAI on vf610 does work with only one clock. So the
driver change will break old DTB for vf610? If that's case, we will
have to need a new compatible for cases where 4 clocks are needed.
Shawn
> + clock-names = "bus", "mclk1", "mclk2", "mclk3";
> status = "disabled";
> };
>
> --
> 1.8.4
>
>
^ permalink raw reply
* Re: [PATCH v2 2/2] ARM: dts: Append clock bindings for sai2 on VF610 platform
From: Nicolin Chen @ 2014-04-02 13:39 UTC (permalink / raw)
To: Shawn Guo
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
broonie, ijc+devicetree, linux-kernel, robh+dt, timur, Li.Xiubo,
rob, galak, linuxppc-dev
In-Reply-To: <20140402130302.GC8558@dragon>
Hi Shawn,
Thanks for the comments, but...
On Wed, Apr 02, 2014 at 09:03:04PM +0800, Shawn Guo wrote:
> On Wed, Apr 02, 2014 at 06:10:20PM +0800, Nicolin Chen wrote:
> > Since we added fours clock to the DT binding, we should update the current
> > SAI dts/dtsi so as not to break their functions.
> >
> > Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
> > ---
> > arch/arm/boot/dts/vf610.dtsi | 6 ++++--
> > 1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi
> > index d31ce1b..9fd0007 100644
> > --- a/arch/arm/boot/dts/vf610.dtsi
> > +++ b/arch/arm/boot/dts/vf610.dtsi
> > @@ -139,8 +139,10 @@
> > compatible = "fsl,vf610-sai";
> > reg = <0x40031000 0x1000>;
> > interrupts = <0 86 0x04>;
> > - clocks = <&clks VF610_CLK_SAI2>;
> > - clock-names = "sai";
> > + clocks = <&clks VF610_CLK_SAI2>,
> > + <&clks VF610_CLK_SAI2>,
> > + <&clks 0>, <&clks 0>;
>
> So it seems that SAI on vf610 does work with only one clock. So the
> driver change will break old DTB for vf610? If that's case, we will
> have to need a new compatible for cases where 4 clocks are needed.
According to Vybrid's RM Chapter 9.11.12 SAI clocking, the SoC actually
connects SAI with two clocks: SAI_CLK and Platform Bus Clock. So the DT
binding here still needs to be corrected even if ignoring driver change.
Besides, I've checked both SAI on imx and vf610 and found that they are
seemly identical, especially for the clock part -- "The transmitter and
receiver can independently select between the bus clock and up to three
audio master clocks to generate the bit clock." And the driver that was
designed for vf610 already contains the code to switch the clock between
Bus Clock and Three MCLKs. What I want to say is, even if SAI on vf610
does work with only one clock, it still doesn't have the full function
on vf610 -- driving clock from Platform Bus Clock unless we make this
improvement to the DT binding.
So I think it's fair to complete the code here for both platforms, even
though we might take the risk of merging conflict. And I understand
your point to avoid function break on those platform both of us aren't
convenient to test. But I've already involved Xiubo in the list. And
we can wait for his test result.
Hope you can understand the circumstance,
Nicolin
^ permalink raw reply
* Re: [RFC PATCH] powerpc/le: enable RTAS events support
From: Greg Kurz @ 2014-04-02 15:56 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Nathan Fontenot, linuxppc-dev@lists.ozlabs.org, Paul Mackerras,
linux-kernel@vger.kernel.org, Anton Blanchard
In-Reply-To: <CAMuHMdXXELjK-t4k025uRE3QPsMiYR9KevtEnq_k32m-4g+fPg@mail.gmail.com>
On Tue, 1 Apr 2014 12:26:32 +0200
Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Mon, Mar 31, 2014 at 5:02 PM, Nathan Fontenot
> <nfont@linux.vnet.ibm.com> wrote:
> > struct rtas_error_log {
> > - unsigned long version:8; /* Architectural version */
> > - unsigned long severity:3; /* Severity level of error */
> > - unsigned long disposition:2; /* Degree of recovery */
> > - unsigned long extended:1; /* extended log present? */
> > - unsigned long /* reserved */ :2; /* Reserved for future use */
> > - unsigned long initiator:4; /* Initiator of event */
> > - unsigned long target:4; /* Target of failed operation */
> > - unsigned long type:8; /* General event or error*/
> > - unsigned long extended_log_length:32; /* length in bytes */
> > - unsigned char buffer[1]; /* Start of extended log */
> > + /* Byte 0 */
> > + uint8_t version; /* Architectural version */
> > +
> > + /* Byte 1 */
> > + uint8_t severity;
> > + /* XXXXXXXX
> > + * XXX 3: Severity level of error
> > + * XX 2: Degree of recovery
> > + * X 1: Extended log present?
> > + * XX 2: Reserved
> > + */
> > +
> > + /* Byte 2 */
> > + uint8_t :8;
> > + /* XXXXXXXX
> > + * XXXX 4: Initiator of event
> > + * XXXX 4: Target of failed operation
> > + */
> > + uint8_t type; /* General event or error*/
> > + uint32_t extended_log_length; /* length in bytes */
>
> Now the bitfields are gone, things like the above can become __be32,
> so we get extra type checking from sparse ("make C=1").
>
> Gr{oetje,eeting}s,
>
> Geert
>
I am reworking a patch in this direction.
Thanks.
--
Greg
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
--
Gregory Kurz kurzgreg@fr.ibm.com
gkurz@linux.vnet.ibm.com
Software Engineer @ IBM/Meiosys http://www.ibm.com
Tel +33 (0)562 165 496
"Anarchy is about taking complete responsibility for yourself."
Alan Moore.
^ permalink raw reply
* [PATCH] powerpc/mm: numa pte should be handled via slow path in get_user_pages_fast
From: Aneesh Kumar K.V @ 2014-04-02 16:07 UTC (permalink / raw)
To: benh, paulus; +Cc: linuxppc-dev, Aneesh Kumar K.V
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
We need to handle numa pte via the slow path
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/mm/gup.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
index c5f734e20b0f..d8746684f606 100644
--- a/arch/powerpc/mm/gup.c
+++ b/arch/powerpc/mm/gup.c
@@ -36,6 +36,11 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
do {
pte_t pte = ACCESS_ONCE(*ptep);
struct page *page;
+ /*
+ * Similar to the PMD case, NUMA hinting must take slow path
+ */
+ if (pte_numa(pte))
+ return 0;
if ((pte_val(pte) & mask) != result)
return 0;
@@ -75,6 +80,14 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
if (pmd_none(pmd) || pmd_trans_splitting(pmd))
return 0;
if (pmd_huge(pmd) || pmd_large(pmd)) {
+ /*
+ * NUMA hinting faults need to be handled in the GUP
+ * slowpath for accounting purposes and so that they
+ * can be serialised against THP migration.
+ */
+ if (pmd_numa(pmd))
+ return 0;
+
if (!gup_hugepte((pte_t *)pmdp, PMD_SIZE, addr, next,
write, pages, nr))
return 0;
--
1.8.3.2
^ permalink raw reply related
* [bug report] bad error path in fsl_open_inb_mbox()
From: Dan Carpenter @ 2014-04-02 16:48 UTC (permalink / raw)
To: linuxppc-dev
Hello PPC devs,
Smatch has the following warning:
arch/powerpc/sysdev/fsl_rmu.c:884 fsl_open_inb_mbox()
error: buffer overflow 'rmu->msg_tx_ring.virt_buffer' 2048 <= 2048
arch/powerpc/sysdev/fsl_rmu.c
861 for (i = 0; i < rmu->msg_rx_ring.size; i++)
862 rmu->msg_rx_ring.virt_buffer[i] = NULL;
Here we set i one past the end of the ->virt_buffer[] array.
863
864 /* Initialize inbound message ring */
865 rmu->msg_rx_ring.virt = dma_alloc_coherent(priv->dev,
866 rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
867 &rmu->msg_rx_ring.phys, GFP_KERNEL);
868 if (!rmu->msg_rx_ring.virt) {
869 rc = -ENOMEM;
870 goto out;
871 }
872
873 /* Point dequeue/enqueue pointers at first entry in ring */
874 out_be32(&rmu->msg_regs->ifqdpar, (u32) rmu->msg_rx_ring.phys);
875 out_be32(&rmu->msg_regs->ifqepar, (u32) rmu->msg_rx_ring.phys);
876
877 /* Clear interrupt status */
878 out_be32(&rmu->msg_regs->isr, 0x00000091);
879
880 /* Hook up inbound message handler */
881 rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0,
882 "msg_rx", (void *)mport);
883 if (rc < 0) {
884 dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
885 rmu->msg_tx_ring.virt_buffer[i],
^^^^^^^^^^^^^^
Wrong variable.
886 rmu->msg_tx_ring.phys_buffer[i]);
^^^^^^^^^^^^^^
This should probably be something like:
dma_free_coherent(priv->dev,
rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
But dma_free_coherent() is poorly documented (it's not documented at
all) and I can't even compile this code so I don't feel comfortable
patching this myself.
Please give me a Reported-by tag if you fix this.
887 goto out;
888 }
regards,
dan carpenter
^ permalink raw reply
* Re: [PATCH 6/7] DMA: Freescale: use spin_lock_bh instead of spin_lock_irqsave
From: Vinod Koul @ 2014-04-02 16:35 UTC (permalink / raw)
To: Hongbo Zhang
Cc: Vinod Koul, linux-kernel, scottwood, dmaengine, dan.j.williams,
linuxppc-dev
In-Reply-To: <5338EA57.1000509@freescale.com>
On Mon, Mar 31, 2014 at 12:08:55PM +0800, Hongbo Zhang wrote:
>
> On 03/29/2014 09:45 PM, Vinod Koul wrote:
> >On Fri, Mar 28, 2014 at 02:33:37PM +0800, Hongbo Zhang wrote:
> >>On 03/26/2014 03:01 PM, Vinod Koul wrote:
> >>>On Thu, 2014-01-16 at 13:47 +0800, hongbo.zhang@freescale.com wrote:
> >>>>From: Hongbo Zhang <hongbo.zhang@freescale.com>
> >>>>
> >>>>The usage of spin_lock_irqsave() is a stronger locking mechanism than is
> >>>>required throughout the driver. The minimum locking required should be used
> >>>>instead. Interrupts will be turned off and context will be saved, it is
> >>>>unnecessary to use irqsave.
> >>>>
> >>>>This patch changes all instances of spin_lock_irqsave() to spin_lock_bh(). All
> >>>>manipulation of protected fields is done using tasklet context or weaker, which
> >>>>makes spin_lock_bh() the correct choice.
> >>>>
> >
> >>>> /**
> >>>>@@ -1124,11 +1120,10 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
> >>>> static void dma_do_tasklet(unsigned long data)
> >>>> {
> >>>> struct fsldma_chan *chan = (struct fsldma_chan *)data;
> >>>>- unsigned long flags;
> >>>> chan_dbg(chan, "tasklet entry\n");
> >>>>- spin_lock_irqsave(&chan->desc_lock, flags);
> >>>>+ spin_lock_bh(&chan->desc_lock);
> >>>okay here is the problem :(
> >>>
> >>>You moved to _bh variant. So if you grab the lock in rest of the code
> >>>and irq gets triggered then here we will be spinning to grab the lock.
> >>>So effectively you made right locking solution into deadlock situation!
> >>If the rest code grabs lock by spin_lock_bh(), and if irq raised,
> >>the tasklet could not be executed because it has been disabled by
> >>the _bh variant function.
> >yes if you are accessing resources only in tasklet and rest of the code, then
> >_bh variant works well. The problem here is usage in irq handler
> >
>
> The name dma_do_tasklet may mislead, it is tasklet handler, not irq
> handler, not a trigger to load tasklet.
> the irq handler is fsldma_chan_irq, and I don't use lock in it.
sorry my bad, i misread this as code in fsldma_chan_irq() insteadof
dma_do_tasklet(). In that case patch is doing the right thing.
--
~Vinod
>
> If it is the problem, I would like to change dma_do_tasklet to
> dma_tasklet to eliminate misleading.
>
>
>
--
^ permalink raw reply
* Re: [RFC PATCH] hugetlb: ensure hugepage access is denied if hugepages are not supported
From: Nishanth Aravamudan @ 2014-04-02 17:16 UTC (permalink / raw)
To: linux-mm; +Cc: paulus, anton, nyc, akpm, linuxppc-dev
In-Reply-To: <20140326155815.GB15234@linux.vnet.ibm.com>
On 26.03.2014 [08:58:15 -0700], Nishanth Aravamudan wrote:
> On 24.03.2014 [16:02:56 -0700], Nishanth Aravamudan wrote:
> > In KVM guests on Power, if the guest is not backed by hugepages, we see
> > the following in the guest:
> >
> > AnonHugePages: 0 kB
> > HugePages_Total: 0
> > HugePages_Free: 0
> > HugePages_Rsvd: 0
> > HugePages_Surp: 0
> > Hugepagesize: 64 kB
> >
> > This seems like a configuration issue -- why is a hstate of 64k being
> > registered?
> >
> > I did some debugging and found that the following does trigger,
> > mm/hugetlb.c::hugetlb_init():
> >
> > /* Some platform decide whether they support huge pages at boot
> > * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
> > * there is no such support
> > */
> > if (HPAGE_SHIFT == 0)
> > return 0;
> >
> > That check is only during init-time. So we don't support hugepages, but
> > none of the hugetlb APIs actually check this condition (HPAGE_SHIFT ==
> > 0), so /proc/meminfo above falsely indicates there is a valid hstate (at
> > least one). But note that there is no /sys/kernel/mm/hugepages meaning
> > no hstate was actually registered.
> >
> > Further, it turns out that huge_page_order(default_hstate) is 0, so
> > hugetlb_report_meminfo is doing:
> >
> > 1UL << (huge_page_order(h) + PAGE_SHIFT - 10)
> >
> > which ends up just doing 1 << (PAGE_SHIFT - 10) and since the base page
> > size is 64k, we report a hugepage size of 64k... And allow the user to
> > allocate hugepages via the sysctl, etc.
> >
> > What's the right thing to do here?
> >
> > 1) Should we add checks for HPAGE_SHIFT == 0 to all the hugetlb APIs? It
> > seems like HPAGE_SHIFT == 0 should be the equivalent, functionally, of
> > the config options being off. This seems like a lot of overhead, though,
> > to put everywhere, so maybe I can do it in an arch-specific macro, that
> > in asm-generic defaults to 0 (and so will hopefully be compiled out?).
> >
> > 2) What should hugetlbfs do when HPAGE_SHIFT == 0? Should it be
> > mountable? Obviously if it's mountable, we can't great files there
> > (since the fs will report insufficient space). [1]
>
> Here is my solution to this. Comments appreciated!
>
> In KVM guests on Power, in a guest not backed by hugepages, we see the
> following:
>
> AnonHugePages: 0 kB
> HugePages_Total: 0
> HugePages_Free: 0
> HugePages_Rsvd: 0
> HugePages_Surp: 0
> Hugepagesize: 64 kB
>
> HPAGE_SHIFT == 0 in this configuration, which indicates that hugepages
> are not supported at boot-time, but this is only checked in
> hugetlb_init(). Extract the check to a helper function, and use it in a
> few relevant places.
>
> This does make hugetlbfs not supported in this environment. I believe
> this is fine, as there are no valid hugepages and that won't change at
> runtime.
>
> Signed-off-by: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
Ping on this? The patch below fixes a pretty easy-to-reproduce bug in
guests under KVM guests on Power.
Thanks,
Nish
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index d19b30a..c7aa477 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -1017,6 +1017,11 @@ static int __init init_hugetlbfs_fs(void)
> int error;
> int i;
>
> + if (!hugepages_supported()) {
> + printk(KERN_ERR "hugetlbfs: Disabling because there are no supported page sizes\n");
> + return -ENOTSUPP;
> + }
> +
> error = bdi_init(&hugetlbfs_backing_dev_info);
> if (error)
> return error;
> diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> index 8c43cc4..0aea8de 100644
> --- a/include/linux/hugetlb.h
> +++ b/include/linux/hugetlb.h
> @@ -450,4 +450,14 @@ static inline spinlock_t *huge_pte_lock(struct hstate *h,
> return ptl;
> }
>
> +static inline bool hugepages_supported(void)
> +{
> + /*
> + * Some platform decide whether they support huge pages at boot
> + * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
> + * there is no such support
> + */
> + return HPAGE_SHIFT != 0;
> +}
> +
> #endif /* _LINUX_HUGETLB_H */
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index c01cb9f..1c99585 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -1949,11 +1949,7 @@ module_exit(hugetlb_exit);
>
> static int __init hugetlb_init(void)
> {
> - /* Some platform decide whether they support huge pages at boot
> - * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
> - * there is no such support
> - */
> - if (HPAGE_SHIFT == 0)
> + if (!hugepages_supported())
> return 0;
>
> if (!size_to_hstate(default_hstate_size)) {
> @@ -2069,6 +2065,9 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
> unsigned long tmp;
> int ret;
>
> + if (!hugepages_supported())
> + return -ENOTSUPP;
> +
> tmp = h->max_huge_pages;
>
> if (write && h->order >= MAX_ORDER)
> @@ -2122,6 +2121,9 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
> unsigned long tmp;
> int ret;
>
> + if (!hugepages_supported())
> + return -ENOTSUPP;
> +
> tmp = h->nr_overcommit_huge_pages;
>
> if (write && h->order >= MAX_ORDER)
> @@ -2147,6 +2149,8 @@ out:
> void hugetlb_report_meminfo(struct seq_file *m)
> {
> struct hstate *h = &default_hstate;
> + if (!hugepages_supported())
> + return;
> seq_printf(m,
> "HugePages_Total: %5lu\n"
> "HugePages_Free: %5lu\n"
> @@ -2163,6 +2167,8 @@ void hugetlb_report_meminfo(struct seq_file *m)
> int hugetlb_report_node_meminfo(int nid, char *buf)
> {
> struct hstate *h = &default_hstate;
> + if (!hugepages_supported())
> + return 0;
> return sprintf(buf,
> "Node %d HugePages_Total: %5u\n"
> "Node %d HugePages_Free: %5u\n"
> @@ -2177,6 +2183,9 @@ void hugetlb_show_meminfo(void)
> struct hstate *h;
> int nid;
>
> + if (!hugepages_supported())
> + return;
> +
> for_each_node_state(nid, N_MEMORY)
> for_each_hstate(h)
> pr_info("Node %d hugepages_total=%u hugepages_free=%u hugepages_surp=%u hugepages_size=%lukB\n",
^ permalink raw reply
* Re: [PATCH RFC v10 0/6] MPC512x DMA slave s/g support, OF DMA lookup
From: Alexander Popov @ 2014-04-02 17:53 UTC (permalink / raw)
To: linuxppc-dev, Gerhard Sittig, Andy Shevchenko, Arnd Bergmann,
dmaengine, Dan Williams, Lars-Peter Clausen, Anatolij Gustschin,
Vinod Koul, a13xp0p0v88
Cc: devicetree
In-Reply-To: <1395326878-25243-1-git-send-email-a13xp0p0v88@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1604 bytes --]
Hello
20.03.2014 18:48 "Alexander Popov" <a13xp0p0v88@gmail.com> wrote:
> Changes in v10:
> Part 2/6:
> - don't use direction field of dma_slave_config in
mpc_dma_device_control()
> but store settings in mpc_dma_chan for both DMA_DEV_TO_MEM and
> DMA_MEM_TO_DEV cases; then retrieve the needed values in
> mpc_dma_prep_slave_sg();
> - fix style issue and put 2014 instead of 2013;
> Part 3/6:
> - fix mpc_dma_probe() error path and mpc_dma_remove(): manually free
IRQs and
> dispose IRQ mappings before devm_* takes care of other resources;
> Part 6/6:
> - change according the new part 3/6;
> - fix style issue;
Could I have a feedback?
Thanks!
> Alexander Popov (5):
> dma: mpc512x: reorder mpc8308 specific instructions
> dma: mpc512x: add support for peripheral transfers
> dma: mpc512x: fix freeing resources in mpc_dma_probe() and
> mpc_dma_remove()
> dma: of: Add common xlate function for matching by channel id
> dma: mpc512x: register for device tree channel lookup
>
> Gerhard Sittig (1):
> dma: mpc512x: add device tree binding document
>
> .../devicetree/bindings/dma/mpc512x-dma.txt | 55 ++++
> arch/powerpc/boot/dts/mpc5121.dtsi | 1 +
> drivers/dma/mpc512x_dma.c | 345
++++++++++++++++++---
> drivers/dma/of-dma.c | 35 +++
> include/linux/of_dma.h | 4 +
> 5 files changed, 402 insertions(+), 38 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/dma/mpc512x-dma.txt
>
> --
> 1.8.4.2
>
Best regards,
Alexander
[-- Attachment #2: Type: text/html, Size: 2038 bytes --]
^ permalink raw reply
* Re: [PATCH v2] spi: add "spi-lsb-first" to devicetree
From: Mark Brown @ 2014-04-02 19:39 UTC (permalink / raw)
To: Zhao Qiang
Cc: B07421, baruch, devicetree, linux-spi, R63061, linuxppc-dev,
wangyuhang2014
In-Reply-To: <1396343450-6199-1-git-send-email-B45475@freescale.com>
[-- Attachment #1: Type: text/plain, Size: 198 bytes --]
On Tue, Apr 01, 2014 at 05:10:50PM +0800, Zhao Qiang wrote:
> add optional property devicetree for SPI slave nodes
> into devicetree so that LSB mode can be enabled by devicetree.
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] ASoC: fsl_sai: Add imx6sx platform support
From: Mark Brown @ 2014-04-02 19:52 UTC (permalink / raw)
To: Nicolin Chen
Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, linux-doc,
ijc+devicetree, linux-kernel, robh+dt, timur, Li.Xiubo, rob,
galak, linuxppc-dev
In-Reply-To: <1396352049-23554-1-git-send-email-Guangyu.Chen@freescale.com>
[-- Attachment #1: Type: text/plain, Size: 340 bytes --]
On Tue, Apr 01, 2014 at 07:34:09PM +0800, Nicolin Chen wrote:
> The next coming i.MX6 Solo X SoC also contains SAI module while we use
> imp_pcm_init() for i.MX platform.
I've applied this, though obviously it'd be better if we had dmaengine
support for this SoC so that it was just a compatible string update and
didn't require any code.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH 1/2] fixup: "powerpc/perf: Add support for the hv 24x7 interface"
From: Cody P Schafer @ 2014-04-02 22:10 UTC (permalink / raw)
To: Michael Ellerman
Cc: Linux PPC, cody+local, LKML, David.Laight, Anton Blanchard,
Cody P Schafer
In-Reply-To: <1396476654-20623-1-git-send-email-cody@linux.vnet.ibm.com>
Make the "not enabled" message less awful.
Signed-off-by: Cody P Schafer <cody@linux.vnet.ibm.com>
---
arch/powerpc/perf/hv-24x7.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c
index 297c9105..3246ea2 100644
--- a/arch/powerpc/perf/hv-24x7.c
+++ b/arch/powerpc/perf/hv-24x7.c
@@ -491,7 +491,7 @@ static int hv_24x7_init(void)
hret = hv_perf_caps_get(&caps);
if (hret) {
- pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+ pr_info("could not obtain capabilities, not enabling (%ld)\n",
hret);
return -ENODEV;
}
--
1.9.1
^ permalink raw reply related
* [PATCH 2/2] fixup: "powerpc/perf: Add support for the hv gpci (get performance counter info) interface"
From: Cody P Schafer @ 2014-04-02 22:10 UTC (permalink / raw)
To: Michael Ellerman
Cc: Linux PPC, cody+local, LKML, David.Laight, Anton Blanchard,
Cody P Schafer
In-Reply-To: <1396476654-20623-1-git-send-email-cody@linux.vnet.ibm.com>
Make the "not enabled" message less awful.
Signed-off-by: Cody P Schafer <cody@linux.vnet.ibm.com>
---
arch/powerpc/perf/hv-gpci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c
index 278ba7b..f6c471d 100644
--- a/arch/powerpc/perf/hv-gpci.c
+++ b/arch/powerpc/perf/hv-gpci.c
@@ -279,7 +279,7 @@ static int hv_gpci_init(void)
hret = hv_perf_caps_get(&caps);
if (hret) {
- pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+ pr_info("could not obtain capabilities, not enabling (%ld)\n",
hret);
return -ENODEV;
}
--
1.9.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox