* [RFC PATCH 09/10] arm64/sve: Enable default vector length control via procfs
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
This patch makes the default SVE vector length at exec() for user tasks
controllable via procfs, in /proc/cpu/sve_default_vector_length.
Limited effort is made to return sensible errors when writing the
procfs file, and anyway the value gets silently clamped to the
maximum VL supported by the platform: users should close and reopen
the file and read back to see the result.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
Caveats:
* /proc may not be the correct place for this (but it's not clear
where in sysfs it should go either, and it's a global control with
no corresponding kobject)
* There seems to be no suitable framework for writable controls of
this sort in /proc (unlike debugfs or sysfs). So, I had to write a
suspiciously large amount of code -- I may have missed an obvious
trick :P
arch/arm64/kernel/fpsimd.c | 160 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 158 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index f010a1c..3c0e08c 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -22,8 +22,12 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/prctl.h>
+#include <linux/proc_fs.h>
#include <linux/sched.h>
+#include <linux/seq_file.h>
#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
#include <linux/hardirq.h>
#include <asm/fpsimd.h>
@@ -102,9 +106,132 @@ void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
/* Maximum supported vector length across all CPUs (initially poisoned) */
int sve_max_vl = -1;
+/* Default VL for tasks that don't set it explicitly: */
+int sve_default_vl = -1;
#ifdef CONFIG_ARM64_SVE
+#ifdef CONFIG_PROC_FS
+
+struct default_vl_write_state {
+ bool invalid;
+ size_t len;
+ char buf[40]; /* enough for "0x" + 64-bit hex integer + NUL */
+};
+
+static int sve_default_vl_show(struct seq_file *s, void *data)
+{
+ seq_printf(s, "%d\n", sve_default_vl);
+ return 0;
+}
+
+static ssize_t sve_default_vl_write(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct default_vl_write_state *state =
+ ((struct seq_file *)f->private_data)->private;
+ long ret;
+
+ if (!size)
+ return 0;
+
+ if (*pos > sizeof(state->buf) ||
+ size >= sizeof(state->buf) - *pos) {
+ ret = -ENOSPC;
+ goto error;
+ }
+
+ ret = copy_from_user(state->buf + *pos, buf, size);
+ if (ret > 0)
+ ret = -EINVAL;
+ if (ret)
+ goto error;
+
+ *pos += size;
+ if (*pos > state->len)
+ state->len = *pos;
+
+ return size;
+
+error:
+ state->invalid = true;
+ return ret;
+}
+
+static int sve_default_vl_release(struct inode *i, struct file *f)
+{
+ int ret = 0;
+ int t;
+ unsigned long value;
+ struct default_vl_write_state *state =
+ ((struct seq_file *)f->private_data)->private;
+
+ if (!(f->f_mode & FMODE_WRITE))
+ goto out;
+
+ if (state->invalid)
+ goto out;
+
+ if (state->len >= sizeof(state->buf)) {
+ WARN_ON(1);
+ state->len = sizeof(state->buf) - 1;
+ }
+
+ state->buf[state->len] = '\0';
+ t = kstrtoul(state->buf, 0, &value);
+ if (t)
+ ret = t;
+
+ if (!sve_vl_valid(value))
+ ret = -EINVAL;
+
+ if (!sve_vl_valid(sve_max_vl)) {
+ WARN_ON(1);
+ ret = -EINVAL;
+ }
+
+ if (value > sve_max_vl)
+ value = sve_max_vl;
+
+ if (!ret)
+ sve_default_vl = value;
+
+out:
+ t = seq_release_private(i, f);
+ return ret ? ret : t;
+}
+
+static int sve_default_vl_open(struct inode *i, struct file *f)
+{
+ struct default_vl_write_state *data = NULL;
+ int ret;
+
+ if (f->f_mode & FMODE_WRITE) {
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->invalid = false;
+ data->len = 0;
+ }
+
+ ret = single_open(f, sve_default_vl_show, data);
+ if (ret)
+ kfree(data);
+
+ return ret;
+}
+
+static const struct file_operations sve_default_vl_fops = {
+ .open = sve_default_vl_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = sve_default_vl_release,
+ .write = sve_default_vl_write,
+};
+
+#endif /* !CONFIG_PROC_FS */
+
static void task_fpsimd_to_sve(struct task_struct *task);
static void task_fpsimd_load(struct task_struct *task);
static void task_fpsimd_save(struct task_struct *task);
@@ -299,7 +426,7 @@ void fpsimd_flush_thread(void)
!(current->thread.sve_flags & THREAD_VL_INHERIT)) {
BUG_ON(!sve_vl_valid(sve_max_vl));
- current->thread.sve_vl = sve_max_vl;
+ current->thread.sve_vl = sve_default_vl;
current->thread.sve_flags = 0;
}
}
@@ -723,6 +850,14 @@ void __init fpsimd_init_task_struct_size(void)
& 0xf) == 1) {
/* FIXME: This should be the minimum across all CPUs */
sve_max_vl = sve_get_vl();
+ sve_default_vl = sve_max_vl;
+
+ /*
+ * To avoid enlarging the signal frame by default, clamp to
+ * 512 bits until/unless overridden by userspace:
+ */
+ if (sve_default_vl > 512 / 8)
+ sve_default_vl = 512 / 8;
arch_task_struct_size = sizeof(struct task_struct) +
35 * sve_max_vl;
@@ -734,6 +869,27 @@ void __init fpsimd_init_task_struct_size(void)
/*
* FP/SIMD support code initialisation.
*/
+static int __init sve_procfs_init(void)
+{
+#if defined(CONFIG_ARM64_SVE) && defined(CONFIG_PROC_FS)
+ struct proc_dir_entry *dir;
+
+ if (!(elf_hwcap & HWCAP_SVE))
+ return 0;
+
+ /* This should be moved elsewhere is anything else ever uses it: */
+ dir = proc_mkdir("cpu", NULL);
+ if (!dir)
+ return -ENOMEM;
+
+ if (!proc_create("sve_default_vector_length",
+ S_IRUGO | S_IWUSR, dir, &sve_default_vl_fops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
static int __init fpsimd_init(void)
{
if (elf_hwcap & HWCAP_FP) {
@@ -749,6 +905,6 @@ static int __init fpsimd_init(void)
if (!(elf_hwcap & HWCAP_SVE))
pr_info("Scalable Vector Extension available\n");
- return 0;
+ return sve_procfs_init();
}
late_initcall(fpsimd_init);
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 08/10] arm64/sve: ptrace: Wire up vector length control and reporting
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
This patch adds support for manipulating a task's vector length at
runtime via ptrace.
As a simplification, we turn the task back into an FPSIMD-only task
when changing the vector length. If the register data is written
too, we then turn the task back into an SVE task, with changed
task_struct layout for the SVE data, before the actual data writing
is done.
Because the vector length is now variable, sve_get() now needs to
return the real maximum for user_sve_header.max_vl, since .vl may
be less than this (that's the whole point).
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/asm/fpsimd.h | 1 +
arch/arm64/include/uapi/asm/ptrace.h | 5 +++++
arch/arm64/kernel/ptrace.c | 25 +++++++++++++++----------
3 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 1ec2363..0f1b068 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -105,6 +105,7 @@ extern void sve_load_state(void const *state, u32 const *pfpsr,
extern unsigned int sve_get_vl(void);
extern int sve_set_vector_length(struct task_struct *task,
unsigned long vl, unsigned long flags);
+extern int sve_max_vl;
/*
* FPSIMD/SVE synchronisation helpers for ptrace:
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 48b57a0..bcb542d 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -64,6 +64,8 @@
#ifndef __ASSEMBLY__
+#include <linux/prctl.h>
+
/*
* User structures for general purpose, floating point and debug registers.
*/
@@ -108,6 +110,9 @@ struct user_sve_header {
#define SVE_PT_REGS_FPSIMD 0
#define SVE_PT_REGS_SVE SVE_PT_REGS_MASK
+#define SVE_PT_VL_THREAD PR_SVE_SET_VL_THREAD
+#define SVE_PT_VL_INHERIT PR_SVE_SET_VL_INHERIT
+
/*
* The remainder of the SVE state follows struct user_sve_header. The
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 32debb8..7e40039 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -741,14 +741,15 @@ static int sve_get(struct task_struct *target,
BUG_ON(!sve_vl_valid(header.vl));
vq = sve_vq_from_vl(header.vl);
- /* Until runtime or per-task vector length changing is supported: */
- header.max_vl = header.vl;
+ BUG_ON(!sve_vl_valid(sve_max_vl));
+ header.max_vl = sve_max_vl;
header.flags = test_tsk_thread_flag(target, TIF_SVE) ?
SVE_PT_REGS_SVE : SVE_PT_REGS_FPSIMD;
header.size = SVE_PT_SIZE(vq, header.flags);
- header.max_size = SVE_PT_SIZE(vq, SVE_PT_REGS_SVE);
+ header.max_size = SVE_PT_SIZE(sve_vq_from_vl(header.max_vl),
+ SVE_PT_REGS_SVE);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header,
0, sizeof(header));
@@ -830,14 +831,18 @@ static int sve_set(struct task_struct *target,
if (ret)
goto out;
- if (header.vl != target->thread.sve_vl)
- return -EINVAL;
-
- BUG_ON(!sve_vl_valid(header.vl));
- vq = sve_vq_from_vl(header.vl);
+ /*
+ * Apart from PT_SVE_REGS_MASK, all PT_SVE_* flags are consumed by
+ * sve_set_vector_length(), which will also validate them for us:
+ */
+ ret = sve_set_vector_length(target, header.vl,
+ header.flags & ~SVE_PT_REGS_MASK);
+ if (ret)
+ goto out;
- if (header.flags & ~SVE_PT_REGS_MASK)
- return -EINVAL;
+ /* Actual VL set may be less than the user asked for: */
+ BUG_ON(!sve_vl_valid(target->thread.sve_vl));
+ vq = sve_vq_from_vl(target->thread.sve_vl);
/* Registers: FPSIMD-only case */
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 07/10] arm64/sve: Add vector length inheritance control
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
Currently the vector length is inherited across both fork() and
exec().
Inheritance across fork() is desirable both for creating a copy of
a process (traditional fork) or creating a thread (where we want
all threads to share the same VL by default).
Inheritance across exec() is less desirable, because of the ABI
impact of large vector lengths on the size of the signal frame --
when running a new binary, there is no guarantee that the new
binary is compatible with these ABI changes.
This flag makes the vector length non-inherited by default.
Instead, the vector length is reset to a system default value,
unless the THREAD_VL_INHERIT flag has been set for the thread.
THREAD_VL_INHERIT is currently sticky: i.e., if set, it gets
inherited too. This behaviour may be refined in future if it is
not flexible enough.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/asm/processor.h | 7 +++++++
arch/arm64/kernel/fpsimd.c | 33 ++++++++++++++++++++++++++-------
include/uapi/linux/prctl.h | 5 +++++
3 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 96eada9..45ef11d 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -27,6 +27,7 @@
#ifdef __KERNEL__
+#include <linux/prctl.h>
#include <linux/string.h>
#include <asm/alternative.h>
@@ -84,11 +85,17 @@ struct thread_struct {
#endif
struct fpsimd_state fpsimd_state;
u16 sve_vl; /* SVE vector length */
+ u16 sve_flags; /* SVE related flags */
unsigned long fault_address; /* fault info */
unsigned long fault_code; /* ESR_EL1 value */
struct debug_info debug; /* debugging */
};
+/* Flags for sve_flags (intentionally defined to match the prctl flags) */
+
+/* Inherit sve_vl and sve_flags across execve(): */
+#define THREAD_VL_INHERIT PR_SVE_SET_VL_INHERIT
+
#ifdef CONFIG_COMPAT
#define task_user_tls(t) \
({ \
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 32caca3..f010a1c 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -292,12 +292,15 @@ void fpsimd_flush_thread(void)
* User tasks must have a valid vector length set, but tasks
* forked early (e.g., init) may not have one yet.
* By now, we will know what the hardware supports, so set the
- * task vector length if it doesn't have one:
+ * task vector length to default if doesn't have one, or if
+ * the thread wasn't configured to inherit SVE configuration:
*/
- if (!current->thread.sve_vl) {
+ if (!current->thread.sve_vl ||
+ !(current->thread.sve_flags & THREAD_VL_INHERIT)) {
BUG_ON(!sve_vl_valid(sve_max_vl));
current->thread.sve_vl = sve_max_vl;
+ current->thread.sve_flags = 0;
}
}
@@ -506,10 +509,10 @@ int sve_set_vector_length(struct task_struct *task,
*/
if (!(flags & PR_SVE_SET_VL_THREAD) && get_nr_threads(task) != 1)
return -EINVAL;
-
flags &= ~(unsigned long)PR_SVE_SET_VL_THREAD;
- if (flags)
- return -EINVAL; /* No other flags defined yet */
+
+ if (flags & ~(unsigned long)PR_SVE_SET_VL_INHERIT)
+ return -EINVAL;
if (!sve_vl_valid(vl))
return -EINVAL;
@@ -542,11 +545,27 @@ int sve_set_vector_length(struct task_struct *task,
task->thread.sve_vl = vl;
+ /* The THREAD_VL_* flag encodings match the relevant PR_* flags: */
+ task->thread.sve_flags = flags;
+
fpsimd_flush_task_state(task);
return 0;
}
+/*
+ * Encode the current vector length and flags for return.
+ * This is only required for prctl(): ptrace has separate fields
+ */
+static int sve_prctl_status(struct task_struct const *task)
+{
+ int ret = task->thread.sve_vl;
+
+ ret |= task->thread.sve_vl << 16;
+
+ return ret;
+}
+
/* PR_SVE_SET_VL */
int sve_set_task_vl(struct task_struct *task,
unsigned long vector_length, unsigned long flags)
@@ -565,7 +584,7 @@ int sve_set_task_vl(struct task_struct *task,
if (ret)
return ret;
- return task->thread.sve_vl;
+ return sve_prctl_status(task);
}
/* PR_SVE_GET_VL */
@@ -574,7 +593,7 @@ int sve_get_task_vl(struct task_struct *task)
if (!(elf_hwcap & HWCAP_SVE))
return -EINVAL;
- return task->thread.sve_vl;
+ return sve_prctl_status(task);
}
#endif /* CONFIG_ARM64_SVE */
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index c55530b..cff6214 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -200,6 +200,11 @@ struct prctl_mm_map {
/* arm64 Scalable Vector Extension controls */
#define PR_SVE_SET_VL 48 /* set task vector length */
# define PR_SVE_SET_VL_THREAD (1 << 1) /* set just this thread */
+# define PR_SVE_SET_VL_INHERIT (1 << 2) /* inherit across exec */
#define PR_SVE_GET_VL 49 /* get task vector length */
+/* Decode helpers for the return value from PR_SVE_GET_VL: */
+# define PR_SVE_GET_VL_LEN(ret) ((ret) & 0x3fff) /* vector length */
+# define PR_SVE_GET_VL_INHERIT (PR_SVE_SET_VL_INHERIT << 16)
+/* For conveinence, PR_SVE_SET_VL returns the result in the same encoding */
#endif /* _LINUX_PRCTL_H */
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 06/10] arm64/sve: Disallow VL setting for individual threads by default
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
General-purpose code in userspace is not expected to work correctly
if multiple threads are allowed to run concurrently with different
vector lengths in a single process.
This patch adds an explicit flag PR_SVE_SET_VL_THREAD to request
this behaviour. Without the flag, vector length setting is
permitted only for a single-threaded process (which matches the
expected usage model of setting the vector length at process
startup).
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/kernel/fpsimd.c | 12 +++++++++++-
include/uapi/linux/prctl.h | 1 +
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 5f2c24a..32caca3 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -21,6 +21,7 @@
#include <linux/cpu_pm.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/prctl.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/hardirq.h>
@@ -498,8 +499,17 @@ int sve_set_vector_length(struct task_struct *task,
{
BUG_ON(task == current && preemptible());
+ /*
+ * To avoid accidents, forbid setting for individual threads of a
+ * multithreaded process. User code that knows what it's doing can
+ * pass PR_SVE_SET_VL_THREAD to override this restriction:
+ */
+ if (!(flags & PR_SVE_SET_VL_THREAD) && get_nr_threads(task) != 1)
+ return -EINVAL;
+
+ flags &= ~(unsigned long)PR_SVE_SET_VL_THREAD;
if (flags)
- return -EINVAL; /* No flags defined yet */
+ return -EINVAL; /* No other flags defined yet */
if (!sve_vl_valid(vl))
return -EINVAL;
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index e32e2da..c55530b 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -199,6 +199,7 @@ struct prctl_mm_map {
/* arm64 Scalable Vector Extension controls */
#define PR_SVE_SET_VL 48 /* set task vector length */
+# define PR_SVE_SET_VL_THREAD (1 << 1) /* set just this thread */
#define PR_SVE_GET_VL 49 /* get task vector length */
#endif /* _LINUX_PRCTL_H */
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 05/10] arm64/sve: Wire up vector length control prctl() calls
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
This patch provides implementation for the PR_SVE_SET_VL and
PR_SVE_GET_VL prctls, which allow a task to set and query its
vector length and associated control flags (although no flags are
defined in this patch).
Currently any thread can set its VL, allowing a mix of VLs within
a single process -- this behaviour will be refined in susequent
patches.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/asm/fpsimd.h | 2 ++
arch/arm64/kernel/fpsimd.c | 65 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 22d09c0..1ec2363 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -103,6 +103,8 @@ extern void sve_save_state(void *state, u32 *pfpsr);
extern void sve_load_state(void const *state, u32 const *pfpsr,
unsigned long vq_minus_1);
extern unsigned int sve_get_vl(void);
+extern int sve_set_vector_length(struct task_struct *task,
+ unsigned long vl, unsigned long flags);
/*
* FPSIMD/SVE synchronisation helpers for ptrace:
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 54d7ed0..5f2c24a 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -493,17 +493,78 @@ void fpsimd_sync_from_fpsimd_zeropad(struct task_struct *task)
__fpsimd_sync_from_fpsimd_zeropad(task, sve_vq_from_vl(vl));
}
+int sve_set_vector_length(struct task_struct *task,
+ unsigned long vl, unsigned long flags)
+{
+ BUG_ON(task == current && preemptible());
+
+ if (flags)
+ return -EINVAL; /* No flags defined yet */
+
+ if (!sve_vl_valid(vl))
+ return -EINVAL;
+
+ if (vl > sve_max_vl) {
+ BUG_ON(!sve_vl_valid(sve_max_vl));
+ vl = sve_max_vl;
+ }
+
+ /*
+ * To ensure the FPSIMD bits of the SVE vector registers are preserved,
+ * write any live register state back to task_struct, and convert to a
+ * non-SVE thread.
+ */
+ if (vl != task->thread.sve_vl) {
+ if (task == current &&
+ !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
+ task_fpsimd_save(current);
+
+ if (test_and_clear_tsk_thread_flag(task, TIF_SVE))
+ task_sve_to_fpsimd(task);
+
+ /*
+ * To avoid surprises, also zero out the SVE regs storage.
+ * This means that the P-regs, FFR and high bits of Z-regs
+ * will read as zero on next access:
+ */
+ clear_sve_regs(task);
+ }
+
+ task->thread.sve_vl = vl;
+
+ fpsimd_flush_task_state(task);
+
+ return 0;
+}
+
/* PR_SVE_SET_VL */
int sve_set_task_vl(struct task_struct *task,
unsigned long vector_length, unsigned long flags)
{
- return -EINVAL;
+ int ret;
+
+ if (!(elf_hwcap & HWCAP_SVE))
+ return -EINVAL;
+
+ BUG_ON(task != current);
+
+ preempt_disable();
+ ret = sve_set_vector_length(current, vector_length, flags);
+ preempt_enable();
+
+ if (ret)
+ return ret;
+
+ return task->thread.sve_vl;
}
/* PR_SVE_GET_VL */
int sve_get_task_vl(struct task_struct *task)
{
- return -EINVAL;
+ if (!(elf_hwcap & HWCAP_SVE))
+ return -EINVAL;
+
+ return task->thread.sve_vl;
}
#endif /* CONFIG_ARM64_SVE */
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 04/10] arm64/sve: Factor out clearing of tasks' SVE regs
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
The patch factors out the code that clears a task's SVE regs on
exec(), so that we can reuse it in subsequent patches.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/kernel/fpsimd.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index ab2bb62..54d7ed0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -260,6 +260,19 @@ void fpsimd_thread_switch(struct task_struct *next)
}
}
+static void clear_sve_regs(struct task_struct *task)
+{
+ BUG_ON(task == current && preemptible());
+
+ BUG_ON((char *)__task_sve_state(task) < (char *)task);
+ BUG_ON(arch_task_struct_size <
+ ((char *)__task_sve_state(task) - (char *)task));
+
+ memset(__task_sve_state(task), 0,
+ arch_task_struct_size -
+ ((char *)__task_sve_state(task) - (char *)task));
+}
+
void fpsimd_flush_thread(void)
{
if (!system_supports_fpsimd())
@@ -272,13 +285,7 @@ void fpsimd_flush_thread(void)
memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
- BUG_ON((char *)__task_sve_state(current) < (char *)current);
- BUG_ON(arch_task_struct_size <
- ((char *)__task_sve_state(current) - (char *)current));
-
- memset(__task_sve_state(current), 0,
- arch_task_struct_size -
- ((char *)__task_sve_state(current) - (char *)current));
+ clear_sve_regs(current);
/*
* User tasks must have a valid vector length set, but tasks
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 03/10] arm64/sve: Set CPU vector length to match current task
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
This patch adds the necessary code to configure the CPU for the
task's vector length, whenever SVE state is loaded for a task.
No special action is needed on sched-out: only user tasks with SVE
state care what the CPU's VL is set to.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/asm/fpsimd.h | 3 ++-
arch/arm64/include/asm/fpsimdmacros.h | 7 ++++++-
arch/arm64/kernel/entry-fpsimd.S | 2 +-
arch/arm64/kernel/fpsimd.c | 10 +++++++---
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index e13259e..22d09c0 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -100,7 +100,8 @@ extern void __init fpsimd_init_task_struct_size(void);
extern void *__task_sve_state(struct task_struct *task);
extern void sve_save_state(void *state, u32 *pfpsr);
-extern void sve_load_state(void const *state, u32 const *pfpsr);
+extern void sve_load_state(void const *state, u32 const *pfpsr,
+ unsigned long vq_minus_1);
extern unsigned int sve_get_vl(void);
/*
diff --git a/arch/arm64/include/asm/fpsimdmacros.h b/arch/arm64/include/asm/fpsimdmacros.h
index e2bb032..7b53bc1 100644
--- a/arch/arm64/include/asm/fpsimdmacros.h
+++ b/arch/arm64/include/asm/fpsimdmacros.h
@@ -254,7 +254,12 @@
.purgem savep
.endm
-.macro sve_load nb, xpfpsr, ntmp
+.macro sve_load nb, xpfpsr, xvqminus1 ntmp
+ mrs_s x\ntmp, ZCR_EL1
+ bic x\ntmp, x\ntmp, ZCR_EL1_LEN_MASK
+ orr x\ntmp, x\ntmp, \xvqminus1
+ msr_s ZCR_EL1, x\ntmp // self-synchronising
+
.macro loadz n
_zldrv \n, \nb, (\n) - 34
.endm
diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S
index 5dcec55..0a3fdcb 100644
--- a/arch/arm64/kernel/entry-fpsimd.S
+++ b/arch/arm64/kernel/entry-fpsimd.S
@@ -73,7 +73,7 @@ ENTRY(sve_save_state)
ENDPROC(sve_save_state)
ENTRY(sve_load_state)
- sve_load 0, x1, 2
+ sve_load 0, x1, x2, 3
ret
ENDPROC(sve_load_state)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 6065707..ab2bb62 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -175,10 +175,14 @@ extern void *__task_pffr(struct task_struct *task);
static void task_fpsimd_load(struct task_struct *task)
{
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
- test_tsk_thread_flag(task, TIF_SVE))
+ test_tsk_thread_flag(task, TIF_SVE)) {
+ unsigned int vl = task->thread.sve_vl;
+
+ BUG_ON(!sve_vl_valid(vl));
sve_load_state(__task_pffr(task),
- &task->thread.fpsimd_state.fpsr);
- else
+ &task->thread.fpsimd_state.fpsr,
+ sve_vq_from_vl(vl) - 1);
+ } else
fpsimd_load_state(&task->thread.fpsimd_state);
/*
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 02/10] arm64/sve: Track vector length for each task
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
In preparation for allowing each task to have its own independent
vector length, this patch adds a sve_vl field to thread_struct to
track it, and interrogates this instead of interrogating the
hardware when knowledge of the task's vector length is needed.
The hardware supported vector length is not known straight out of
boot, so init_task and other kernel tasks forked early may lack
this knowledge.
We only need this knowledge when in the context of a user task that
has SVE state (or that has just trapped while attempting to have
SVE state). So, we can hook into exec() to set task vector length
if it wasn't known at boot/fork time, before the task enters
userspace.
There is no way to change sve_vl for a task yet, so all tasks still
execute with the hardware vector length. Subsequent patches will
enable changing the vector length for tasks.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/asm/processor.h | 1 +
arch/arm64/kernel/fpsimd.c | 44 ++++++++++++++++++++++++++------------
arch/arm64/kernel/ptrace.c | 4 ++--
arch/arm64/kernel/signal.c | 15 +++++++++----
4 files changed, 44 insertions(+), 20 deletions(-)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 6f0f300..96eada9 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -83,6 +83,7 @@ struct thread_struct {
unsigned long tp2_value;
#endif
struct fpsimd_state fpsimd_state;
+ u16 sve_vl; /* SVE vector length */
unsigned long fault_address; /* fault info */
unsigned long fault_code; /* ESR_EL1 value */
struct debug_info debug; /* debugging */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index bdacfcd..6065707 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -99,6 +99,9 @@ void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
WARN_ON(1);
}
+/* Maximum supported vector length across all CPUs (initially poisoned) */
+int sve_max_vl = -1;
+
#ifdef CONFIG_ARM64_SVE
static void task_fpsimd_to_sve(struct task_struct *task);
@@ -156,9 +159,9 @@ void *__task_sve_state(struct task_struct *task)
static void *__task_pffr(struct task_struct *task)
{
- unsigned int vl = sve_get_vl();
+ unsigned int vl = task->thread.sve_vl;
- BUG_ON(vl % 16);
+ BUG_ON(!sve_vl_valid(vl));
return (char *)__task_sve_state(task) + 34 * vl;
}
@@ -272,6 +275,18 @@ void fpsimd_flush_thread(void)
memset(__task_sve_state(current), 0,
arch_task_struct_size -
((char *)__task_sve_state(current) - (char *)current));
+
+ /*
+ * User tasks must have a valid vector length set, but tasks
+ * forked early (e.g., init) may not have one yet.
+ * By now, we will know what the hardware supports, so set the
+ * task vector length if it doesn't have one:
+ */
+ if (!current->thread.sve_vl) {
+ BUG_ON(!sve_vl_valid(sve_max_vl));
+
+ current->thread.sve_vl = sve_max_vl;
+ }
}
set_thread_flag(TIF_FOREIGN_FPSTATE);
@@ -310,16 +325,15 @@ static void __task_sve_to_fpsimd(struct task_struct *task, unsigned int vq)
static void task_sve_to_fpsimd(struct task_struct *task)
{
- unsigned int vl = sve_get_vl();
+ unsigned int vl = task->thread.sve_vl;
unsigned int vq;
if (!(elf_hwcap & HWCAP_SVE))
return;
- BUG_ON(vl % 16);
- vq = vl / 16;
- BUG_ON(vq < 1 || vq > 16);
+ BUG_ON(!sve_vl_valid(vl));
+ vq = sve_vq_from_vl(vl);
__task_sve_to_fpsimd(task, vq);
}
@@ -373,16 +387,15 @@ static void __task_fpsimd_to_sve(struct task_struct *task, unsigned int vq)
static void task_fpsimd_to_sve(struct task_struct *task)
{
- unsigned int vl = sve_get_vl();
+ unsigned int vl = task->thread.sve_vl;
unsigned int vq;
if (!(elf_hwcap & HWCAP_SVE))
return;
- BUG_ON(vl % 16);
- vq = vl / 16;
- BUG_ON(vq < 1 || vq > 16);
+ BUG_ON(!sve_vl_valid(vl));
+ vq = sve_vq_from_vl(vl);
__task_fpsimd_to_sve(task, vq);
}
@@ -463,8 +476,9 @@ static void __fpsimd_sync_from_fpsimd_zeropad(struct task_struct *task,
void fpsimd_sync_from_fpsimd_zeropad(struct task_struct *task)
{
- unsigned int vl = sve_get_vl();
+ unsigned int vl = task->thread.sve_vl;
+ BUG_ON(!sve_vl_valid(vl));
__fpsimd_sync_from_fpsimd_zeropad(task, sve_vq_from_vl(vl));
}
@@ -606,11 +620,13 @@ void __init fpsimd_init_task_struct_size(void)
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
((read_cpuid(ID_AA64PFR0_EL1) >> ID_AA64PFR0_SVE_SHIFT)
& 0xf) == 1) {
- arch_task_struct_size = sizeof(struct task_struct) +
- 35 * sve_get_vl();
+ /* FIXME: This should be the minimum across all CPUs */
+ sve_max_vl = sve_get_vl();
+ arch_task_struct_size = sizeof(struct task_struct) +
+ 35 * sve_max_vl;
pr_info("SVE: enabled with maximum %u bits per vector\n",
- sve_get_vl() * 8);
+ sve_max_vl * 8);
}
}
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index fb8cef63..32debb8 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -736,7 +736,7 @@ static int sve_get(struct task_struct *target,
/* Header */
memset(&header, 0, sizeof(header));
- header.vl = sve_get_vl();
+ header.vl = target->thread.sve_vl;
BUG_ON(!sve_vl_valid(header.vl));
vq = sve_vq_from_vl(header.vl);
@@ -830,7 +830,7 @@ static int sve_set(struct task_struct *target,
if (ret)
goto out;
- if (header.vl != sve_get_vl())
+ if (header.vl != target->thread.sve_vl)
return -EINVAL;
BUG_ON(!sve_vl_valid(header.vl));
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 9ef9953..7615c7d 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -222,8 +222,11 @@ static int preserve_sve_context(struct sve_context __user *ctx)
{
int err = 0;
u16 reserved[ARRAY_SIZE(ctx->__reserved)];
- unsigned int vl = sve_get_vl();
- unsigned int vq = sve_vq_from_vl(vl);
+ unsigned int vl = current->thread.sve_vl;
+ unsigned int vq;
+
+ BUG_ON(!sve_vl_valid(vl));
+ vq = sve_vq_from_vl(vl);
memset(reserved, 0, sizeof(reserved));
@@ -253,7 +256,7 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
__task_sve_state(current);
struct fpsimd_state fpsimd;
- if (vl != sve_get_vl())
+ if (vl != current->thread.sve_vl)
return -EINVAL;
set_thread_flag(TIF_FOREIGN_FPSTATE);
@@ -543,7 +546,11 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
}
if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) {
- unsigned int vq = sve_vq_from_vl(sve_get_vl());
+ unsigned int vl = current->thread.sve_vl;
+ unsigned int vq;
+
+ BUG_ON(!sve_vl_valid(vl));
+ vq = sve_vq_from_vl(vl);
BUG_ON(!(elf_hwcap & HWCAP_SVE));
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 01/10] prctl: Add skeleton for PR_SVE_{SET, GET}_VL controls
From: Dave Martin @ 2017-01-12 11:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com>
This patch adds a do-nothing skeleton for the arm64 Scalable Vector
Extension control prctls.
These prctls are only avilable with
CONFIG_ARM64=y
CONFIG_ARM64_SVE=y
Otherwise they will compile out and return -EINVAL if attempted
from userspace.
The backend functions sve_{set,get}_task_vl() will be fleshed out
with actual functionality in subsequent patches.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
There will probably also be a call to discover the signal frame size
(MINSIGSTKSZ equivalent) for the current configuration, something like
* PR_GET_MINSIGSTKSZ
This series doesn't add this yet: only the PR_SVE_{SET,GET}_VL prctls
are provided.
arch/arm64/include/asm/fpsimd.h | 19 +++++++++++++++++++
arch/arm64/include/asm/processor.h | 4 ++++
arch/arm64/kernel/fpsimd.c | 13 +++++++++++++
include/uapi/linux/prctl.h | 4 ++++
kernel/sys.c | 12 ++++++++++++
5 files changed, 52 insertions(+)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 88bcf69..e13259e 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -17,6 +17,7 @@
#define __ASM_FP_H
#include <asm/ptrace.h>
+#include <asm/errno.h>
#ifndef __ASSEMBLY__
@@ -110,12 +111,30 @@ extern unsigned int sve_get_vl(void);
extern void fpsimd_sync_to_sve(struct task_struct *task);
#ifdef CONFIG_ARM64_SVE
+
extern void fpsimd_sync_to_fpsimd(struct task_struct *task);
extern void fpsimd_sync_from_fpsimd_zeropad(struct task_struct *task);
+extern int sve_set_task_vl(struct task_struct *task,
+ unsigned long vector_length, unsigned long flags);
+extern int sve_get_task_vl(struct task_struct *task);
+
#else /* !CONFIG_ARM64_SVE */
+
static void __maybe_unused fpsimd_sync_to_fpsimd(struct task_struct *task) { }
static void __maybe_unused fpsimd_sync_from_fpsimd_zeropad(
struct task_struct *task) { }
+
+static int __maybe_unused sve_set_task_vl(struct task_struct *task,
+ unsigned long vector_length, unsigned long flags)
+{
+ return -EINVAL;
+}
+
+static int __maybe_unused sve_get_task_vl(struct task_struct *task)
+{
+ return -EINVAL;
+}
+
#endif /* !CONFIG_ARM64_SVE */
#endif
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 747c65a..6f0f300 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -190,4 +190,8 @@ int cpu_enable_pan(void *__unused);
int cpu_enable_uao(void *__unused);
int cpu_enable_cache_maint_trap(void *__unused);
+#define SVE_SET_VL(task, vector_length, flags) \
+ sve_set_task_vl(task, vector_length, flags)
+#define SVE_GET_VL(task) sve_get_task_vl(task)
+
#endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 2c113e4..bdacfcd 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -468,6 +468,19 @@ void fpsimd_sync_from_fpsimd_zeropad(struct task_struct *task)
__fpsimd_sync_from_fpsimd_zeropad(task, sve_vq_from_vl(vl));
}
+/* PR_SVE_SET_VL */
+int sve_set_task_vl(struct task_struct *task,
+ unsigned long vector_length, unsigned long flags)
+{
+ return -EINVAL;
+}
+
+/* PR_SVE_GET_VL */
+int sve_get_task_vl(struct task_struct *task)
+{
+ return -EINVAL;
+}
+
#endif /* CONFIG_ARM64_SVE */
#ifdef CONFIG_KERNEL_MODE_NEON
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index a8d0759..e32e2da 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -197,4 +197,8 @@ struct prctl_mm_map {
# define PR_CAP_AMBIENT_LOWER 3
# define PR_CAP_AMBIENT_CLEAR_ALL 4
+/* arm64 Scalable Vector Extension controls */
+#define PR_SVE_SET_VL 48 /* set task vector length */
+#define PR_SVE_GET_VL 49 /* get task vector length */
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index 842914e..5f50385 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -103,6 +103,12 @@
#ifndef SET_FP_MODE
# define SET_FP_MODE(a,b) (-EINVAL)
#endif
+#ifndef SVE_SET_VL
+# define SVE_SET_VL(a,b,c) (-EINVAL)
+#endif
+#ifndef SVE_GET_VL
+# define SVE_GET_VL(a) (-EINVAL)
+#endif
/*
* this is where the system-wide overflow UID and GID are defined, for
@@ -2261,6 +2267,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_GET_FP_MODE:
error = GET_FP_MODE(me);
break;
+ case PR_SVE_SET_VL:
+ error = SVE_SET_VL(me, arg2, arg3);
+ break;
+ case PR_SVE_GET_VL:
+ error = SVE_GET_VL(me);
+ break;
default:
error = -EINVAL;
break;
--
2.1.4
^ permalink raw reply related
* [RFC PATCH 00/10] arm64/sve: Add userspace vector length control API
From: Dave Martin @ 2017-01-12 11:25 UTC (permalink / raw)
To: linux-arm-kernel
This is an add-on series for the Scalable Vector Extension (SVE) core
patches [1], adding an interface to allow userspace tasks to control
what vector length they use for SVE instructions.
(For an architectural overview of SVE, and an explanation of what a
"vector length" is, see [2].)
The amount of SVE register state depends on the vector length, so using
large vector lengths with SVE can requre the userspace signal frame to
grow. This leads to some ABI impacts in common with other arches that
may have to grow their signal frame.
In this series I do not dictate any particular policy for the SVE vector
length: the kernel provides a default, but userspace can set the vector
length as it likes, provided the hardware supports the chosen length.
For example, userspace may pick a length that the images being loaded
have been validated against or optimised for.
Overview
========
The API proposed here consists of prctl() calls to allow a task to
set/query its vector length and related control flags, and corresponding
ptrace extensions to allow a debugger to do the same for a traced task:
prctl():
* PR_SVE_SET_VL
* PR_SVE_GET_VL
ptrace() NT_ARM_SVE regset:
* user_sve_header.flags & SVE_PT_VL_*
* user_sve_header.vl
(I follow the existing convention of not including the arch name in
prctl names).
The context switch logic is also extended to set the correct vector
length when scheduling a task in, since the vector length may now differ
between tasks.
The expected users of this API are libc startup, dynamic linker and
runtime environment plumbing code. I don't expect ordinary user code to
change its own vector length on-the-fly, partly because it is generally
The Wrong Thing To Do with respect to the SVE programming model, and
partly because of ABI subtleties which make it difficult to do this
correctly.
ABI Impact
==========
The current arm64 signal frame size is not sufficient to save all SVE
state for larger vector lengths.
This won't affect existing binary distros, since the signal frame is not
extended unless some SVE instructions are executed by the user task.
However, non-SVE code executing in the same processes as SVE-aware code
may start to see the kernel using more than MINSIGSTKSZ bytes of stack
to deliver a signal, which may lead to stack overruns. Other ABI
breakages are also possible if we were to simply increase the
MINSIGSTKSZ #define. SVE aware code will need to move to a new
mechanism to discover the signal frame size: perhaps a new prctl() (not
implemented in this series).
As a temporary workaround, I added a Kconfig option in [1] to clamp the
vector length to a safe maximum that hides this effect, but this was
only intended as a short-term kludge.
This series removes the Kconfig kludge and introduces a new runtime
mechanism:
# echo <vector length in bytes> >/proc/cpu/sve_default_vector_length
will now set the default vector length for newly-exec'd processes. This
is initialised to the ABI-safe value 512 at boot (or the maximum value
supported by the hardware, if smaller). Administrators / distro
maintainers / developers can set this to something different in boot
scripts if they are comfortable doing so, or to see what happens.
We _could_ increase the kernel default in the future when and if we are
satisfied that the change is sufficiently low-impact.
User tasks can always override the default via prctl(): the logic is
that non-SVE-aware code doesn't know how to change the vector length,
and so won't do that anyway. SVE-aware code is presumed to understand
the consequences.
The vector length can be made inheritable (allowing implementation of
taskset-like tools, or running a testsuite with a particular vector
length) or not (for general-purpose processes; in which case the vector
length is reset to the default across exec).
[1] arm64: Scalable Vector Extension core support
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/470507.html
[2] Technology Update: The Scalable Vector Extension (SVE) for the ARMv8-A architecture
https://www.community.arm.com/processors/b/blog/posts/technology-update-the-scalable-vector-extension-sve-for-the-armv8-a-architecture
Note: The size of an SVE vector register (the "vector length") is
choosable per hardware implementation, and the ISA allows software to be
coded independently of the actual vector length in use. The vector
length can also be selected explicitly by software within the limits
supported by the hardware -- this is expected to be useful in some
situations. This series exposes this control to userspace.
Dave Martin (10):
prctl: Add skeleton for PR_SVE_{SET,GET}_VL controls
arm64/sve: Track vector length for each task
arm64/sve: Set CPU vector length to match current task
arm64/sve: Factor out clearing of tasks' SVE regs
arm64/sve: Wire up vector length control prctl() calls
arm64/sve: Disallow VL setting for individual threads by default
arm64/sve: Add vector length inheritance control
arm64/sve: ptrace: Wire up vector length control and reporting
arm64/sve: Enable default vector length control via procfs
Revert "arm64/sve: Limit vector length to 512 bits by default"
arch/arm64/Kconfig | 35 ----
arch/arm64/include/asm/fpsimd.h | 25 ++-
arch/arm64/include/asm/fpsimdmacros.h | 7 +-
arch/arm64/include/asm/processor.h | 12 ++
arch/arm64/include/uapi/asm/ptrace.h | 5 +
arch/arm64/kernel/entry-fpsimd.S | 2 +-
arch/arm64/kernel/fpsimd.c | 334 +++++++++++++++++++++++++++++++---
arch/arm64/kernel/ptrace.c | 27 +--
arch/arm64/kernel/signal.c | 15 +-
arch/arm64/mm/proc.S | 5 -
include/uapi/linux/prctl.h | 10 +
kernel/sys.c | 12 ++
12 files changed, 407 insertions(+), 82 deletions(-)
--
2.1.4
^ permalink raw reply
* [PATCH v8 2/5] i2c: Add STM32F4 I2C driver
From: M'boumba Cedric Madianga @ 2017-01-12 11:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170111154200.xcxdlnnakyttumzw@pengutronix.de>
Hi Uwe,
2017-01-11 16:42 GMT+01:00 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
> Hello Cedric,
>
> On Wed, Jan 11, 2017 at 03:20:41PM +0100, M'boumba Cedric Madianga wrote:
>> >
>> >> + */
>> >> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> >> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_POS);
>> >
>> > You could get rid of this, when caching the value of CR1. Would save two
>> > register reads here. This doesn't work for all registers, but it should
>> > be possible to apply for most of them, maybe enough to get rid of the
>> > clr_bits and set_bits function.
>>
>> I agree at many places I could save registers read by not using
>> clr_bits and set_bits function when the registers in question has been
>> already read.
>> But it is not enough to get rid of the clr_bits and set_bits function.
>> For example when calling stm32f4_i2c_terminate_xfer(), the CR1
>> register is never read before so set_bits function is useful.
>
> I didn't double check the manual, but I would expect that CR1 isn't
> modified by hardware. So you can cache the result in the driver data
> structure and do the necessary modifications with that one.
CR1 is modified by hardware to clear some bits set by software during
the communication.
>
> Best regards
> Uwe
>
> --
> Pengutronix e.K. | Uwe Kleine-K?nig |
> Industrial Linux Solutions | http://www.pengutronix.de/ |
Best regards,
Cedric
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: juno: Adds missing CoreSight STM component.
From: Mike Leach @ 2017-01-12 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0120ef9b-2e01-e00a-2de8-c540ab70af85@arm.com>
Hi Sudeep,
I'm fine with that - less duplication the better.
I've not played with .dts files much to I hadn't realised that type of construction was possible.
Regards
Mike
----------------------------------------------------------------
Mike Leach +44 (0)1254 893911 (Direct)
Principal Engineer +44 (0)1254 893900 (Main)
Arm Blackburn Design Centre +44 (0)1254 893901 (Fax)
Belthorn House
Walker Rd mailto:mike.leach at arm.com
Guide
Blackburn
BB1 2QE
----------------------------------------------------------------
> -----Original Message-----
> From: CoreSight [mailto:coresight-bounces at lists.linaro.org] On Behalf Of
> Sudeep Holla
> Sent: 12 January 2017 11:15
> To: Mike Leach; Liviu Dudau; Lorenzo Pieralisi
> Cc: coresight at lists.linaro.org; Suzuki Poulose; linux-arm-
> kernel at lists.infradead.org; Sudeep Holla
> Subject: Re: [PATCH v2 2/2] arm64: dts: juno: Adds missing CoreSight STM
> component.
>
>
>
> On 11/01/17 20:44, Mike Leach wrote:
> > Add missing CoreSight STM component definition to Juno CoreSight
> > infrastructure juno-cs-rX.dtsi files.
> >
> > Component connected to different funnels depending on Juno platform
> variant.
> >
> > Signed-off-by: Mike Leach <mike.leach@linaro.org>
> > ---
> > arch/arm64/boot/dts/arm/juno-cs-r0.dtsi | 16 ++++++++++++++++
> > arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi | 16 ++++++++++++++++
> > 2 files changed, 32 insertions(+)
> >
>
> Can we avoid duplication with something like below ? I don't have strong
> opinion but I just saw the opportunity. I can squash it in if you
> agree(no need to repost).
>
> Regards,
> Sudeep
>
> -->8
>
> diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi
> b/arch/arm64/boot/dts/arm/juno-base.dtsi
> index 7c89000f954d..15fcd09d9d84 100644
> --- a/arch/arm64/boot/dts/arm/juno-base.dtsi
> +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi
> @@ -83,6 +83,21 @@
> * The actual size is just 4K though 64K is reserved. Access to the
> * unmapped reserved region results in a DECERR response.
> */
> +stm at 20100000 {
> +compatible = "arm,coresight-stm", "arm,primecell";
> +reg = <0 0x20100000 0 0x1000>,
> + <0 0x28000000 0 0x180000>;
> +reg-names = "stm-base", "stm-stimulus-base";
> +
> +clocks = <&soc_smc50mhz>;
> +clock-names = "apb_pclk";
> +power-domains = <&scpi_devpd 0>;
> +port {
> +stm_out_port: endpoint {
> +};
> +};
> +};
> +
> etm0: etm at 22040000 {
> compatible = "arm,coresight-etm4x", "arm,primecell";
> reg = <0 0x22040000 0 0x1000>;
> diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts
> b/arch/arm64/boot/dts/arm/juno-r1.dts
> index 881339536e90..1c16a96ff677 100644
> --- a/arch/arm64/boot/dts/arm/juno-r1.dts
> +++ b/arch/arm64/boot/dts/arm/juno-r1.dts
> @@ -228,3 +228,7 @@
> &gpu1_thermal_zone {
> status = "okay";
> };
> +
> +&stm_out_port {
> +remote-endpoint = <&csys1_funnel_in_port0>;
> +};
> diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts
> b/arch/arm64/boot/dts/arm/juno-r2.dts
> index fca3a1705114..69890cc1edae 100644
> --- a/arch/arm64/boot/dts/arm/juno-r2.dts
> +++ b/arch/arm64/boot/dts/arm/juno-r2.dts
> @@ -228,3 +228,7 @@
> &gpu1_thermal_zone {
> status = "okay";
> };
> +
> +&stm_out_port {
> +remote-endpoint = <&csys1_funnel_in_port0>;
> +};
> diff --git a/arch/arm64/boot/dts/arm/juno.dts
> b/arch/arm64/boot/dts/arm/juno.dts
> index c90c37b66db5..ad270e090ba4 100644
> --- a/arch/arm64/boot/dts/arm/juno.dts
> +++ b/arch/arm64/boot/dts/arm/juno.dts
> @@ -204,3 +204,7 @@
> &etm5 {
> cpu = <&A53_3>;
> };
> +
> +&stm_out_port {
> +remote-endpoint = <&main_funnel_in_port2>;
> +};
>
> _______________________________________________
> CoreSight mailing list
> CoreSight at lists.linaro.org
> https://lists.linaro.org/mailman/listinfo/coresight
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
^ permalink raw reply
* [PATCH 56/62] watchdog: tangox_wdt: Convert to use device managed functions
From: Måns Rullgård @ 2017-01-12 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0f68aa11-161b-0435-ea0f-851432464bc1@sigmadesigns.com>
Marc Gonzalez <marc_gonzalez@sigmadesigns.com> writes:
>> So far we have a claim that a cast to a void * may somehow be different
>> to a cast to a different pointer, if used as function argument, and that
>> the behavior with such a cast may be undefined. In other words, you claim
>> that a function implemented as, say,
>>
>> void func(int *var) {}
>>
>> might result in undefined behavior if some header file declares it as
>>
>> void func(void *);
>>
>> and it is called as
>>
>> int var;
>>
>> func(&var);
>>
>> That seems really far fetched to me.
>
> Thanks for giving me an opportunity to play the language lawyer :-)
>
> C99 6.3.2.3 sub-clause 8 states:
>
> "A pointer to a function of one type may be converted to a pointer to
> a function of another type and back again; the result shall compare
> equal to the original pointer. If a converted pointer is used to call
> a function whose type is not compatible with the pointed-to type, the
> behavior is undefined."
>
> So, the behavior is undefined, not when you cast clk_disable_unprepare,
> but when clk_disable_unprepare is later called through the devres->action
> function pointer.
Only if the function types are incompatible. C99 6.7.5.3 subclause 15:
For two function types to be compatible, both shall specify compatible
return types. Moreover, the parameter type lists, if both are
present, shall agree in the number of parameters and in use of the
ellipsis terminator; corresponding parameters shall have compatible
types.
The question then is whether pointer to void and pointer to struct clk
are compatible types. 6.7.5.1 subclause 2:
For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types.
6.2.5 subclause 27:
A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type. 39)
39) The same representation and alignment requirements are meant to
imply interchangeability as arguments to functions, return values
from functions, and members of unions.
6.3.2.3 subclause 1:
A pointer to void may be converted to or from a pointer to any
incomplete or object type.
>From what I can tell, the standard stops just short of declaring pointer
to void compatible with other pointer types.
> However, I agree that it will work as expected on typical platforms
> (where all pointers are the same size, and the calling convention
> treats all pointers the same).
Yes, I don't see how it could possibly go wrong.
--
M?ns Rullg?rd
^ permalink raw reply
* [PATCH v8 2/5] i2c: Add STM32F4 I2C driver
From: M'boumba Cedric Madianga @ 2017-01-12 11:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170111153940.dtxzvtdici3r7l54@pengutronix.de>
2017-01-11 16:39 GMT+01:00 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
> On Wed, Jan 11, 2017 at 02:58:44PM +0100, M'boumba Cedric Madianga wrote:
>> Hi Uwe,
>>
>> 2017-01-11 9:22 GMT+01:00 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
>> > Hello Cedric,
>> >
>> > On Thu, Jan 05, 2017 at 10:07:23AM +0100, M'boumba Cedric Madianga wrote:
>> >> +/*
>> >> + * In standard mode:
>> >> + * SCL period = SCL high period = SCL low period = CCR * I2C parent clk period
>> >> + *
>> >> + * In fast mode:
>> >> + * If Duty = 0; SCL high period = 1 * CCR * I2C parent clk period
> ^^
>> >> + * SCL low period = 2 * CCR * I2C parent clk period
> ^^
>> >> + * If Duty = 1; SCL high period = 9 * CCR * I2C parent clk period
> ^^
>> >> + * SCL low period = 16 * CCR * I2C parent clk period
>
>> > s/ \*/ */ several times
>>
>> Sorry but I don't see where is the issue as the style for multi-line
>> comments seems ok.
>> Could you please clarify that point if possible ? Thanks in advance
>
> There are several places with double spaces before * marked above.
Ok I see thanks.
>
>> >> + * In order to reach 400 kHz with lower I2C parent clk frequencies we always set
>> >> + * Duty = 1
>> >> + *
>> >> + * For both modes, we have CCR = SCL period * I2C parent clk frequency
>> >> + * with scl_period = 5 microseconds in Standard mode and scl_period = 1
>> > s/mode/Mode/
>>
>> ok thanks
>>
>> >
>> >> + * microsecond in Fast Mode in order to satisfy scl_high and scl_low periods
>> >> + * constraints defined by i2c bus specification
>> >
>> > I don't understand scl_period = 1 ?s for Fast Mode. For a bus freqency
>> > of 400 kHz we need low + high = 2.5 ?s. Is there a factor 10 missing
>> > somewhere?
>>
>> As CCR = SCL_period * I2C parent clk frequency with minimal freq =
>> 2Mhz and SCL_period = 1 we have:
>> CCR = 1 * 2Mhz = 2.
>> But to compute, scl_low and scl_high in Fast mode, we have to do the
>> following thing as Duty=1:
>> scl_high = 9 * CCR * I2C parent clk period
>> scl_low = 16 * CCR * I2C parent clk period
>> In our example:
>> scl_high = 9 * 2 * 0,0000005 = 0,000009 sec = 9 ?s
>> scl_low = 16 * 2 * 0.0000005 = 0,000016 sec = 16 ?s
>> So low + high = 27 ?s > 2,5 ?s
>
> For me 9 ?s + 16 ?s is 25 ?s, resulting in 40 kHz. That's why I wondered
> if there is a factor 10 missing somewhere.
Hum ok. I am going to double-check what is wrong because when I check
with the scope I always reach 400Khz for SCL.
I will let you know.
>
>> >> + */
>> >> +static struct stm32f4_i2c_timings i2c_timings[] = {
>> >> [...]
>> >> +
>> >> +/**
>> >> + * stm32f4_i2c_hw_config() - Prepare I2C block
>> >> + * @i2c_dev: Controller's private data
>> >> + */
>> >> +static int stm32f4_i2c_hw_config(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >> + void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
>> >> + int ret = 0;
>> >> +
>> >> + /* Disable I2C */
>> >> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_PE);
>> >> +
>> >> + ret = stm32f4_i2c_set_periph_clk_freq(i2c_dev);
>> >> + if (ret)
>> >> + return ret;
>> >> +
>> >> + stm32f4_i2c_set_rise_time(i2c_dev);
>> >> +
>> >> + stm32f4_i2c_set_speed_mode(i2c_dev);
>> >> +
>> >> + stm32f4_i2c_set_filter(i2c_dev);
>> >> +
>> >> + /* Enable I2C */
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_PE);
>> >
>> > This function is called after a hw reset, so there should be no need to
>> > use clr_bits and set_bits because the value read from hw should be
>> > known.
>>
>> ok thanks
>>
>> >
>> >> + return ret;
>> >
>> > return 0;
>>
>> ok thanks
>>
>> >
>> >> +}
>> >> +
>> >> +static int stm32f4_i2c_wait_free_bus(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >> + u32 status;
>> >> + int ret;
>> >> +
>> >> + ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F4_I2C_SR2,
>> >> + status,
>> >> + !(status & STM32F4_I2C_SR2_BUSY),
>> >> + 10, 1000);
>> >> + if (ret) {
>> >> + dev_dbg(i2c_dev->dev, "bus not free\n");
>> >> + ret = -EBUSY;
>> >> + }
>> >> +
>> >> + return ret;
>> >> +}
>> >> +
>> >> +/**
>> >> + * stm32f4_i2c_write_ byte() - Write a byte in the data register
>> >> + * @i2c_dev: Controller's private data
>> >> + * @byte: Data to write in the register
>> >> + */
>> >> +static void stm32f4_i2c_write_byte(struct stm32f4_i2c_dev *i2c_dev, u8 byte)
>> >> +{
>> >> + writel_relaxed(byte, i2c_dev->base + STM32F4_I2C_DR);
>> >> +}
>> >> +
>> >> +/**
>> >> + * stm32f4_i2c_write_msg() - Fill the data register in write mode
>> >> + * @i2c_dev: Controller's private data
>> >> + *
>> >> + * This function fills the data register with I2C transfer buffer
>> >> + */
>> >> +static void stm32f4_i2c_write_msg(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> >> +
>> >> + stm32f4_i2c_write_byte(i2c_dev, *msg->buf++);
>> >> + msg->count--;
>> >> +}
>> >> +
>> >> +static void stm32f4_i2c_read_msg(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> >> + u32 rbuf;
>> >> +
>> >> + rbuf = readl_relaxed(i2c_dev->base + STM32F4_I2C_DR);
>> >> + *msg->buf++ = rbuf & 0xff;
>> >
>> > This is unnecessary. buf has an 8 bit wide type so
>> >
>> > *msg->buf++ = rbuf;
>> >
>> > has the same effect. (ISTR this is something I already pointed out
>> > earlier?)
>>
>> Yes you are right.
>>
>> >
>> >> + msg->count--;
>> >> +}
>> >> +
>> >> +static void stm32f4_i2c_terminate_xfer(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> >> + void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
>> >> +
>> >> + stm32f4_i2c_disable_irq(i2c_dev);
>> >> +
>> >> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> >> + if (msg->stop)
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
>> >> + else
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
>> >> +
>> >> + complete(&i2c_dev->complete);
>> >> +}
>> >> +
>> >> +/**
>> >> + * stm32f4_i2c_handle_write() - Handle FIFO empty interrupt in case of write
>> >> + * @i2c_dev: Controller's private data
>> >> + */
>> >> +static void stm32f4_i2c_handle_write(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> >> + void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
>> >> +
>> >> + if (msg->count) {
>> >> + stm32f4_i2c_write_msg(i2c_dev);
>> >> + if (!msg->count) {
>> >> + /* Disable buffer interrupts for RXNE/TXE events */
>> >> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
>> >> + }
>> >> + } else {
>> >> + stm32f4_i2c_terminate_xfer(i2c_dev);
>> >
>> > Is stm32f4_i2c_terminate_xfer also called when arbitration is lost? If
>> > yes, is it then right to set STM32F4_I2C_CR1_STOP or
>> > STM32F4_I2C_CR1_START?
>>
>> If arbitration is lost, stm32f4_i2c_terminate_xfer() is not called.
>> In that case, we return -EAGAIN and i2c-core will retry by calling
>> stm32f4_i2c_xfer()
>>
>> >
>> >> + }
>> >> +}
>> >> +
>> >> +/**
>> >> + * stm32f4_i2c_handle_read() - Handle FIFO empty interrupt in case of read
>> >> + * @i2c_dev: Controller's private data
>> >> + */
>> >> +static void stm32f4_i2c_handle_read(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> >> + void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
>> >> +
>> >> + switch (msg->count) {
>> >> + case 1:
>> >> + stm32f4_i2c_disable_irq(i2c_dev);
>> >> + stm32f4_i2c_read_msg(i2c_dev);
>> >> + complete(&i2c_dev->complete);
>> >> + break;
>> >> + /*
>> >> + * For 2 or 3-byte reception, we do not have to read the data register
>> >> + * when RXNE occurs as we have to wait for byte transferred finished
>> >
>> > it's hard to understand because if you don't know the hardware the
>> > meaning of RXNE is unknown.
>>
>> Ok I will replace RXNE by RX not empty in that comment
>>
>> >
>> >> + * event before reading data. So, here we just disable buffer
>> >> + * interrupt in order to avoid another system preemption due to RXNE
>> >> + * event
>> >> + */
>> >> + case 2:
>> >> + case 3:
>> >> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
>> >> + break;
>> >> + /* For N byte reception with N > 3 we directly read data register */
>> >> + default:
>> >> + stm32f4_i2c_read_msg(i2c_dev);
>> >> + }
>> >> +}
>> >> +
>> >> +/**
>> >> + * stm32f4_i2c_handle_rx_btf() - Handle byte transfer finished interrupt
>> >> + * in case of read
>> >> + * @i2c_dev: Controller's private data
>> >> + */
>> >> +static void stm32f4_i2c_handle_rx_btf(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >
>> > btf is a hw-related name. Maybe better use _done which is easier to
>> > understand?
>>
>> OK
>>
>> >
>> >> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> >> + void __iomem *reg;
>> >> + u32 mask;
>> >> + int i;
>> >> +
>> >> + switch (msg->count) {
>> >> + case 2:
>> >> + /*
>> >> + * In order to correctly send the Stop or Repeated Start
>> >> + * condition on the I2C bus, the STOP/START bit has to be set
>> >> + * before reading the last two bytes.
>> >> + * After that, we could read the last two bytes, disable
>> >> + * remaining interrupts and notify the end of xfer to the
>> >> + * client
>> >
>> > This is surprising. I didn't recheck the manual, but that looks very
>> > uncomfortable.
>>
>> I agree but this exactly the hardware way of working described in the
>> reference manual.
>
> IMHO that's a hw bug. This makes it for example impossible to implement
> SMBus block transfers (I think).
This is not correct.
Setting STOP/START bit does not mean the the pulse will be sent right now.
Here we have just to prepare the hardware for the 2 next pulse but the
STOP/START/ACK pulse will be generated at the right time as required
by I2C specification.
So SMBus block transfer will be possible.
>
>> > How does this work, when I only want to read a single
>> > byte? Same problem for ACK below.
>>
>> For a single reception, we enable NACK and STOP or Repeatead START
>> bits during address match.
>> The NACK and STOP/START pulses are sent as soon as the data is
>> received in the shift register.
>> Please note that in that case, we don't have to wait BTF event to read the data.
>> Data is read as soon as RXNE event occurs.
>>
>> >
>> >> + */
>> >> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> >> + if (msg->stop)
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
>> >> + else
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
>> >> +
>> >> + for (i = 2; i > 0; i--)
>> >> + stm32f4_i2c_read_msg(i2c_dev);
>> >> +
>> >> + reg = i2c_dev->base + STM32F4_I2C_CR2;
>> >> + mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
>> >> + stm32f4_i2c_clr_bits(reg, mask);
>> >> +
>> >> + complete(&i2c_dev->complete);
>> >> + break;
>> >> + case 3:
>> >> + /*
>> >> + * In order to correctly send the ACK on the I2C bus for the
>> >> + * last two bytes, we have to set ACK bit before reading the
>> >> + * third last data byte
>> >> + */
>> >> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> >> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> >> + stm32f4_i2c_read_msg(i2c_dev);
>> >> + break;
>> >> + default:
>> >> + stm32f4_i2c_read_msg(i2c_dev);
>> >> + }
>> >> +}
>> >> +
>> >> +/**
>> >> + * stm32f4_i2c_handle_rx_addr() - Handle address matched interrupt in case of
>> >> + * master receiver
>> >> + * @i2c_dev: Controller's private data
>> >> + */
>> >> +static void stm32f4_i2c_handle_rx_addr(struct stm32f4_i2c_dev *i2c_dev)
>> >> +{
>> >> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> >> + void __iomem *reg;
>> >> +
>> >> + switch (msg->count) {
>> >> + case 0:
>> >> + stm32f4_i2c_terminate_xfer(i2c_dev);
>> >> + /* Clear ADDR flag */
>> >> + readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> >> + break;
>> >> + case 1:
>> >> + /*
>> >> + * Single byte reception:
>> >
>> > This also happens for the last byte of a 5 byte transfer, right?
>>
>> For a 5 byte transfer the behavior is different:
>> We have to read data from DR (data register) as soon as the RXNE (RX
>> not empty) event occurs for data1, data2 and data3 (until N-2 data for
>> a more generic case)
>> The ACK is automatically sent as soon as the data is received in the
>> shift register as the I2C controller was configured to do that during
>> adress match phase.
>>
>> For data3 (N-2 data), we wait for BTF (Byte Transfer finished) event
>> in order to set NACK before reading DR.
>> This event occurs when a new data has been received in shift register
>> (in our case data4 or N-1 data) but the prevoius data in DR (in our
>> case data3 or N-2 data) has not been read yet.
>> In that way, the NACK pulse will be correctly generated after the last
>> received data byte.
>>
>> For data4 and data5, we wait for BTF event (data4 or N-1 data in DR
>> and data5 or N data in shift register), set STOP or repeated Start in
>> order to correctly sent the right pulse after the last received data
>> byte and run 2 consecutives read of DR.
>
> So "Single byte reception" above is wrong, as this case is also used for
> longer transfers and should be updated accordingly.
I don't think so.
stm32f4_i2c_handle_rx_addr() is called once during adress match phase.
It is used to configure the I2C controller according to the number of
data to be received as it has to be done in a different way according
to the number of data to received:
- single byte reception
- 2-byte reception
- N-byte reception
Then, as soon as, the controller is correctly configured, for each
byte to be received, we use stm32f4_i2c_handle_read() or
stm32f4_i2c_handle_rx_done().
stm32f4_i2c_handle_read() is used to read data for a single byte
reception or until N-2 data for N-byte reception
stm32f4_i2c_handle_rx_done() is used to read data for a 2-byte
reception, or data N-2, N-1 and N for a N-byte reception.
So, single-reception and longer transfer have been clearly managed in
a different way.
>
>> >> + * Enable NACK, clear ADDR flag and generate STOP or RepSTART
>> >> + */
>> >> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> >> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> >> + readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> >> + if (msg->stop)
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
>> >> + else
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
>> >> + break;
>> >> + case 2:
>> >> + /*
>> >> + * 2-byte reception:
>> >> + * Enable NACK and set POS
>> >
>> > What is POS?
>> POS is used to define the position of the (N)ACK pulse
>> 0: ACK is generated when the current is being received in the shift register
>> 1: ACK is generated when the next byte which will be received in the
>> shift register (used for 2-byte reception)
>
> Can you please put this into the comment. "POS" isn't much helpful
> there.
Ok I will add a comment for that.
>
>>
>> >
>> >> + */
>> >> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> >> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_POS);
>> >
>> > You could get rid of this, when caching the value of CR1. Would save two
>> > register reads here. This doesn't work for all registers, but it should
>> > be possible to apply for most of them, maybe enough to get rid of the
>> > clr_bits and set_bits function.
>> >
>> >> + readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> >> + break;
>> >> +
>> >> + default:
>> >> + /* N-byte reception: Enable ACK */
>> >> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> >> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_ACK);
>> >
>> > Do you need to set ACK for each byte transferred?
>> I need to do that in order to be SMBus compatible and the ACK/NACK
>> seems to be used by default in Documentation/i2c/i2c-protocol file.
>
> Yeah, protocol wise you need to ack each byte. I just wondered if you
> need to set the hardware bit for each byte or if it is retained in
> hardware until unset by a register write.
ACK bit is set in stm32f4_i2c_handle_rx_addr().
As explained above, this function is called once during address match phase.
So, this bit is set only once just before receiving the first data byte.
>
> Best regards
> Uwe
>
> --
> Pengutronix e.K. | Uwe Kleine-K?nig |
> Industrial Linux Solutions | http://www.pengutronix.de/ |
Best regards,
Cedric
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: juno: Adds missing CoreSight STM component.
From: Sudeep Holla @ 2017-01-12 11:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484167449-14432-3-git-send-email-mike.leach@linaro.org>
On 11/01/17 20:44, Mike Leach wrote:
> Add missing CoreSight STM component definition to Juno CoreSight
> infrastructure juno-cs-rX.dtsi files.
>
> Component connected to different funnels depending on Juno platform variant.
>
> Signed-off-by: Mike Leach <mike.leach@linaro.org>
> ---
> arch/arm64/boot/dts/arm/juno-cs-r0.dtsi | 16 ++++++++++++++++
> arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi | 16 ++++++++++++++++
> 2 files changed, 32 insertions(+)
>
Can we avoid duplication with something like below ? I don't have strong
opinion but I just saw the opportunity. I can squash it in if you
agree(no need to repost).
Regards,
Sudeep
-->8
diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi
b/arch/arm64/boot/dts/arm/juno-base.dtsi
index 7c89000f954d..15fcd09d9d84 100644
--- a/arch/arm64/boot/dts/arm/juno-base.dtsi
+++ b/arch/arm64/boot/dts/arm/juno-base.dtsi
@@ -83,6 +83,21 @@
* The actual size is just 4K though 64K is reserved. Access to the
* unmapped reserved region results in a DECERR response.
*/
+ stm at 20100000 {
+ compatible = "arm,coresight-stm", "arm,primecell";
+ reg = <0 0x20100000 0 0x1000>,
+ <0 0x28000000 0 0x180000>;
+ reg-names = "stm-base", "stm-stimulus-base";
+
+ clocks = <&soc_smc50mhz>;
+ clock-names = "apb_pclk";
+ power-domains = <&scpi_devpd 0>;
+ port {
+ stm_out_port: endpoint {
+ };
+ };
+ };
+
etm0: etm at 22040000 {
compatible = "arm,coresight-etm4x", "arm,primecell";
reg = <0 0x22040000 0 0x1000>;
diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts
b/arch/arm64/boot/dts/arm/juno-r1.dts
index 881339536e90..1c16a96ff677 100644
--- a/arch/arm64/boot/dts/arm/juno-r1.dts
+++ b/arch/arm64/boot/dts/arm/juno-r1.dts
@@ -228,3 +228,7 @@
&gpu1_thermal_zone {
status = "okay";
};
+
+&stm_out_port {
+ remote-endpoint = <&csys1_funnel_in_port0>;
+};
diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts
b/arch/arm64/boot/dts/arm/juno-r2.dts
index fca3a1705114..69890cc1edae 100644
--- a/arch/arm64/boot/dts/arm/juno-r2.dts
+++ b/arch/arm64/boot/dts/arm/juno-r2.dts
@@ -228,3 +228,7 @@
&gpu1_thermal_zone {
status = "okay";
};
+
+&stm_out_port {
+ remote-endpoint = <&csys1_funnel_in_port0>;
+};
diff --git a/arch/arm64/boot/dts/arm/juno.dts
b/arch/arm64/boot/dts/arm/juno.dts
index c90c37b66db5..ad270e090ba4 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -204,3 +204,7 @@
&etm5 {
cpu = <&A53_3>;
};
+
+&stm_out_port {
+ remote-endpoint = <&main_funnel_in_port2>;
+};
^ permalink raw reply related
* [PATCH] rtc: armada38x: avoid unused-function warning
From: Arnd Bergmann @ 2017-01-12 11:13 UTC (permalink / raw)
To: linux-arm-kernel
When CONFIG_PM_SLEEP is not set, rtc_update_mbus_timing_params becomes
unused, now that armada38x_rtc_probe() no longer calls
rtc_update_mbus_timing_params on startup:
drivers/rtc/rtc-armada38x.c:79:13: error: 'rtc_update_mbus_timing_params' defined but not used [-Werror=unused-function]
This addresses the warning by marking the PM functions as __maybe_unused,
so the unused functions get silently dropped. I could not tell from
the changelog if dropping the call to armada38x_rtc_probe() was
intended here, and if that is the correct thing to do without
CONFIG_PM_SLEEP, so we might need a different fix that brings it back.
Fixes: 4c492eb022c2 ("rtc: armada38x: make struct rtc_class_ops const")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/rtc/rtc-armada38x.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
index 4f75c619bbba..2e451acccd9c 100644
--- a/drivers/rtc/rtc-armada38x.c
+++ b/drivers/rtc/rtc-armada38x.c
@@ -338,8 +338,7 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int armada38x_rtc_suspend(struct device *dev)
+static int __maybe_unused armada38x_rtc_suspend(struct device *dev)
{
if (device_may_wakeup(dev)) {
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
@@ -350,7 +349,7 @@ static int armada38x_rtc_suspend(struct device *dev)
return 0;
}
-static int armada38x_rtc_resume(struct device *dev)
+static int __maybe_unused armada38x_rtc_resume(struct device *dev)
{
if (device_may_wakeup(dev)) {
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
@@ -363,7 +362,6 @@ static int armada38x_rtc_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops,
armada38x_rtc_suspend, armada38x_rtc_resume);
--
2.9.0
^ permalink raw reply related
* [RFC PATCH v4 0/5] ARM: Fix dma_alloc_coherent() and friends for NOMMU
From: Benjamin Gaignard @ 2017-01-12 10:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CA+M3ks5jTNSLLOetvOUZP=B=a2wPNjXadbw6Zcn475Okc4QEPw@mail.gmail.com>
2017-01-12 11:35 GMT+01:00 Benjamin Gaignard <benjamin.gaignard@linaro.org>:
> 2017-01-11 15:34 GMT+01:00 Vladimir Murzin <vladimir.murzin@arm.com>:
>> On 11/01/17 13:17, Benjamin Gaignard wrote:
>>> 2017-01-10 15:18 GMT+01:00 Vladimir Murzin <vladimir.murzin@arm.com>:
>>>> Hi,
>>>>
>>>> It seem that addition of cache support for M-class cpus uncovered
>>>> latent bug in DMA usage. NOMMU memory model has been treated as being
>>>> always consistent; however, for R/M classes of cpu memory can be
>>>> covered by MPU which in turn might configure RAM as Normal
>>>> i.e. bufferable and cacheable. It breaks dma_alloc_coherent() and
>>>> friends, since data can stuck in caches now or be buffered.
>>>>
>>>> This patch set is trying to address the issue by providing region of
>>>> memory suitable for consistent DMA operations. It is supposed that
>>>> such region is marked by MPU as non-cacheable. Robin suggested to
>>>> advertise such memory as reserved shared-dma-pool, rather then using
>>>> homebrew command line option, and extend dma-coherent to provide
>>>> default DMA area in the similar way as it is done for CMA (PATCH
>>>> 2/5). It allows us to offload all bookkeeping on generic coherent DMA
>>>> framework, and it is seems that it might be reused by other
>>>> architectures like c6x and blackfin.
>>>>
>>>> Dedicated DMA region is required for cases other than:
>>>> - MMU/MPU is off
>>>> - cpu is v7m w/o cache support
>>>> - device is coherent
>>>>
>>>> In case one of the above conditions is true dma operations are forced
>>>> to be coherent and wired with dma_noop_ops.
>>>>
>>>> To make life easier NOMMU dma operations are kept in separate
>>>> compilation unit.
>>>>
>>>> Since the issue was reported in the same time as Benjamin sent his
>>>> patch [1] to allow mmap for NOMMU, his case is also addressed in this
>>>> series (PATCH 1/5 and PATCH 3/5).
>>>>
>>>> Thanks!
>>>
>>> I have tested this v4 on my setup (stm32f4, no cache, no MPU) and unfortunately
>>> it doesn't work with my drm/kms driver.
>>
>> I guess the same is for fbmem, but would be better to have confirmation since
>> amba-clcd I use has not been ported to drm/kms (yet), so I can't test.
>>
>>> I haven't any errors but nothing is displayed unlike what I have when
>>> using current dma-mapping
>>> code.
>>> I guess the issue is coming from dma-noop where __get_free_pages() is
>>> used instead of alloc_pages()
>>> in dma-mapping.
>>
>> Unless I've missed something bellow is a call stack for both
>>
>> #1
>> __alloc_simple_buffer
>> __dma_alloc_buffer
>> alloc_pages
>> split_page
>> __dma_clear_buffer
>> memset
>> page_address
>>
>> #2
>> __get_free_pages
>> alloc_pages
>> page_address
>>
>> So the difference is that nommu case in dma-mapping.c memzeros memory, handles
>> DMA_ATTR_NO_KERNEL_MAPPING and does optimisation of memory usage.
>>
>> Is something from above critical for your driver?
>
> I have removed all the diff (split_page, __dma_clear_buffer, memset)
> from #1 and it is still working.
> DMA_ATTR_NO_KERNEL_MAPPING flag is not set when allocating the buffer.
>
> I have investigated more and found that dma-noop doesn't take care of
> "dma-ranges" property which is set in DT.
> I believed that is the root cause of my problem with your patches.
After testing changing virt_to_phys to virt_to_dma in dma-noop.c fix the issue
modetest and fbdemo are now still functional.
>
> Benjamin
>
>>
>>>
>>> Since my hardware doesn't have cache or MPU (and so use dma-noop) I
>>> haven't reserved specific memory region.
>>> Buffer addresses and vma parameters look correct... What could I have
>>> miss here ?
>>
>> No ideas, sorry...
>>
>> Cheers
>> Vladimir
>>
>>>
>>> Benjamin
>>>
>>>>
>>>> [1] http://www.armlinux.org.uk/developer/patches/viewpatch.php?id=8633/1
>>>>
>>>> Vladimir Murzin (5):
>>>> dma: Add simple dma_noop_mmap
>>>> drivers: dma-coherent: Introduce default DMA pool
>>>> ARM: NOMMU: Introduce dma operations for noMMU
>>>> ARM: NOMMU: Set ARM_DMA_MEM_BUFFERABLE for M-class cpus
>>>> ARM: dma-mapping: Remove traces of NOMMU code
>>>>
>>>> .../bindings/reserved-memory/reserved-memory.txt | 3 +
>>>> arch/arm/include/asm/dma-mapping.h | 3 +-
>>>> arch/arm/mm/Kconfig | 2 +-
>>>> arch/arm/mm/Makefile | 5 +-
>>>> arch/arm/mm/dma-mapping-nommu.c | 252 +++++++++++++++++++++
>>>> arch/arm/mm/dma-mapping.c | 26 +--
>>>> drivers/base/dma-coherent.c | 59 ++++-
>>>> lib/dma-noop.c | 21 ++
>>>> 8 files changed, 335 insertions(+), 36 deletions(-)
>>>> create mode 100644 arch/arm/mm/dma-mapping-nommu.c
>>>>
>>>> --
>>>> 2.0.0
>>>>
>>>
>>>
>>>
>>
>
>
>
> --
> Benjamin Gaignard
>
> Graphic Study Group
>
> Linaro.org ? Open source software for ARM SoCs
>
> Follow Linaro: Facebook | Twitter | Blog
--
Benjamin Gaignard
Graphic Study Group
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH] ARM: dts: dra72-evm-revc: fix typo in ethernet-phy node
From: Sekhar Nori @ 2017-01-12 10:54 UTC (permalink / raw)
To: linux-arm-kernel
Fix a typo in impedance setting for ethernet-phy at 3
Fixes: b76db38cd8ae ("ARM: dts: dra72-evm-revc: add phy impedance settings")
Cc: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
arch/arm/boot/dts/dra72-evm-revc.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/dra72-evm-revc.dts b/arch/arm/boot/dts/dra72-evm-revc.dts
index c3d939c9666c..3f808a47df03 100644
--- a/arch/arm/boot/dts/dra72-evm-revc.dts
+++ b/arch/arm/boot/dts/dra72-evm-revc.dts
@@ -75,6 +75,6 @@
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
ti,tx-internal-delay = <DP83867_RGMIIDCTL_250_PS>;
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>;
- ti,min-output-imepdance;
+ ti,min-output-impedance;
};
};
--
2.9.0
^ permalink raw reply related
* [PATCH v2] Documentation: dt: reset: Revise typos in TI syscon reset example
From: Philipp Zabel @ 2017-01-12 10:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170112012217.18115-1-s-anna@ti.com>
Am Mittwoch, den 11.01.2017, 19:22 -0600 schrieb Suman Anna:
> Fix couple of typos in the example given in the TI syscon reset
> binding. The ti,reset-bits used for DSP0 are corrected to match
> the values that will be used in the actual DT node.
>
> Signed-off-by: Suman Anna <s-anna@ti.com>
> ---
> v2: Address Rob Herring's comment to change the reset node name
> from "psc-reset" to "reset-controller"
I've applied the patch, thank you.
regards
Philipp
^ permalink raw reply
* kvm: deadlock in kvm_vgic_map_resources
From: Andre Przywara @ 2017-01-12 10:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170112104253.GB13547@cbox>
Hi,
On 12/01/17 10:42, Christoffer Dall wrote:
> On Thu, Jan 12, 2017 at 10:30:39AM +0000, Marc Zyngier wrote:
>> On 12/01/17 09:55, Andre Przywara wrote:
>>> Hi,
>>>
>>> On 12/01/17 09:32, Marc Zyngier wrote:
>>>> Hi Dmitry,
>>>>
>>>> On 11/01/17 19:01, Dmitry Vyukov wrote:
>>>>> Hello,
>>>>>
>>>>> While running syzkaller fuzzer I've got the following deadlock.
>>>>> On commit 9c763584b7c8911106bb77af7e648bef09af9d80.
>>>>>
>>>>>
>>>>> =============================================
>>>>> [ INFO: possible recursive locking detected ]
>>>>> 4.9.0-rc6-xc2-00056-g08372dd4b91d-dirty #50 Not tainted
>>>>> ---------------------------------------------
>>>>> syz-executor/20805 is trying to acquire lock:
>>>>> (
>>>>> &kvm->lock
>>>>> ){+.+.+.}
>>>>> , at:
>>>>> [< inline >] kvm_vgic_dist_destroy
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:271
>>>>> [<ffff2000080ea4bc>] kvm_vgic_destroy+0x34/0x250
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:294
>>>>> but task is already holding lock:
>>>>> (&kvm->lock){+.+.+.}, at:
>>>>> [<ffff2000080ea7e4>] kvm_vgic_map_resources+0x2c/0x108
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:343
>>>>> other info that might help us debug this:
>>>>> Possible unsafe locking scenario:
>>>>> CPU0
>>>>> ----
>>>>> lock(&kvm->lock);
>>>>> lock(&kvm->lock);
>>>>> *** DEADLOCK ***
>>>>> May be due to missing lock nesting notation
>>>>> 2 locks held by syz-executor/20805:
>>>>> #0:(&vcpu->mutex){+.+.+.}, at:
>>>>> [<ffff2000080bcc30>] vcpu_load+0x28/0x1d0
>>>>> arch/arm64/kvm/../../../virt/kvm/kvm_main.c:143
>>>>> #1:(&kvm->lock){+.+.+.}, at:
>>>>> [<ffff2000080ea7e4>] kvm_vgic_map_resources+0x2c/0x108
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:343
>>>>> stack backtrace:
>>>>> CPU: 2 PID: 20805 Comm: syz-executor Not tainted
>>>>> 4.9.0-rc6-xc2-00056-g08372dd4b91d-dirty #50
>>>>> Hardware name: Hardkernel ODROID-C2 (DT)
>>>>> Call trace:
>>>>> [<ffff200008090560>] dump_backtrace+0x0/0x3c8 arch/arm64/kernel/traps.c:69
>>>>> [<ffff200008090948>] show_stack+0x20/0x30 arch/arm64/kernel/traps.c:219
>>>>> [< inline >] __dump_stack lib/dump_stack.c:15
>>>>> [<ffff200008895840>] dump_stack+0x100/0x150 lib/dump_stack.c:51
>>>>> [< inline >] print_deadlock_bug kernel/locking/lockdep.c:1728
>>>>> [< inline >] check_deadlock kernel/locking/lockdep.c:1772
>>>>> [< inline >] validate_chain kernel/locking/lockdep.c:2250
>>>>> [<ffff2000081c8718>] __lock_acquire+0x1938/0x3440 kernel/locking/lockdep.c:3335
>>>>> [<ffff2000081caa84>] lock_acquire+0xdc/0x1d8 kernel/locking/lockdep.c:3746
>>>>> [< inline >] __mutex_lock_common kernel/locking/mutex.c:521
>>>>> [<ffff200009700004>] mutex_lock_nested+0xdc/0x7b8 kernel/locking/mutex.c:621
>>>>> [< inline >] kvm_vgic_dist_destroy
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:271
>>>>> [<ffff2000080ea4bc>] kvm_vgic_destroy+0x34/0x250
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:294
>>>>> [<ffff2000080ec290>] vgic_v2_map_resources+0x218/0x430
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-v2.c:295
>>>>> [<ffff2000080ea884>] kvm_vgic_map_resources+0xcc/0x108
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:348
>>>>> [< inline >] kvm_vcpu_first_run_init
>>>>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:505
>>>>> [<ffff2000080d2768>] kvm_arch_vcpu_ioctl_run+0xab8/0xce0
>>>>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:591
>>>>> [<ffff2000080c1fec>] kvm_vcpu_ioctl+0x434/0xc08
>>>>> arch/arm64/kvm/../../../virt/kvm/kvm_main.c:2557
>>>>> [< inline >] vfs_ioctl fs/ioctl.c:43
>>>>> [<ffff200008450c38>] do_vfs_ioctl+0x128/0xfc0 fs/ioctl.c:679
>>>>> [< inline >] SYSC_ioctl fs/ioctl.c:694
>>>>> [<ffff200008451b78>] SyS_ioctl+0xa8/0xb8 fs/ioctl.c:685
>>>>> [<ffff200008083ef0>] el0_svc_naked+0x24/0x28 arch/arm64/kernel/entry.S:755
>>>>
>>>> Nice catch, and many thanks for reporting this.
>>>>
>>>> The bug is fairly obvious. Christoffer, what do you think? I don't think
>>>> we need to hold the kvm->lock all the way, but I'd like another pair of
>>>> eyes (the coffee machine is out of order again, and tea doesn't cut it).
>>>>
>>>> Thanks,
>>>>
>>>> M.
>>>>
>>>> From 93f80b20fb9351a49ee8b74eed3fc59c84651371 Mon Sep 17 00:00:00 2001
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>> Date: Thu, 12 Jan 2017 09:21:56 +0000
>>>> Subject: [PATCH] KVM: arm/arm64: vgic: Fix deadlock on error handling
>>>>
>>>> Dmitry Vyukov reported that the syzkaller fuzzer triggered a
>>>> deadlock in the vgic setup code when an error was detected, as
>>>> the cleanup code tries to take a lock that is already held by
>>>> the setup code.
>>>>
>>>> The fix is pretty obvious: move the cleaup call after having
>>>> dropped the lock, since not much can happen at that point.
>>> ^^^^^^^^
>>> Is that really true? If for instance the calls to
>>> vgic_register_dist_iodev() or kvm_phys_addr_ioremap() in
>>> vgic_v2_map_resources() fail, we leave the function with a half
>>> initialized VGIC (because vgic_init() succeeded).
>>
>> But we only set dist->ready to true when everything went OK. How is
>> that an issue?
>>
>>> Dropping the lock at
>>> this point without having the GIC cleaned up before sounds a bit
>>> suspicious (I may be wrong on this, though).
>>
>> Thinking of it, that may open a race with vgic init call, leading to
>> leaking distributor memory.
>>
>>>
>>> Can't we just document that kvm_vgic_destroy() needs to be called with
>>> the kvm->lock held and take the lock around the only other caller
>>> (kvm_arch_destroy_vm() in arch/arm/kvm/arm.c)?
>>> We can then keep holding the lock in the map_resources calls.
>>> Though we might still move the calls to kvm_vgic_destroy() into the
>>> wrapper function as a cleanup (as shown below), just before dropping the
>>> lock.
>>
>> I'd rather keep the changes limited to the vgic code, and save myself
>> having to document more locking (we already have our fair share here).
>> How about this (untested):
>>
>> From 24dc3f5750da20d89e0ce9b7855d125d0100bee8 Mon Sep 17 00:00:00 2001
>> From: Marc Zyngier <marc.zyngier@arm.com>
>> Date: Thu, 12 Jan 2017 09:21:56 +0000
>> Subject: [PATCH] KVM: arm/arm64: vgic: Fix deadlock on error handling
>>
>> Dmitry Vyukov reported that the syzkaller fuzzer triggered a
>> deadlock in the vgic setup code when an error was detected, as
>> the cleanup code tries to take a lock that is already held by
>> the setup code.
>>
>> The fix is to avoid retaking the lock when cleaning up, by
>> telling the cleanup function that we already hold it.
>>
>> Cc: stable at vger.kernel.org
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>> virt/kvm/arm/vgic/vgic-init.c | 21 ++++++++++++++++-----
>> virt/kvm/arm/vgic/vgic-v2.c | 2 --
>> virt/kvm/arm/vgic/vgic-v3.c | 2 --
>> 3 files changed, 16 insertions(+), 9 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
>> index 5114391..30d74e2 100644
>> --- a/virt/kvm/arm/vgic/vgic-init.c
>> +++ b/virt/kvm/arm/vgic/vgic-init.c
>> @@ -264,11 +264,12 @@ int vgic_init(struct kvm *kvm)
>> return ret;
>> }
>>
>> -static void kvm_vgic_dist_destroy(struct kvm *kvm)
>> +static void kvm_vgic_dist_destroy(struct kvm *kvm, bool locked)
>> {
>> struct vgic_dist *dist = &kvm->arch.vgic;
>>
>> - mutex_lock(&kvm->lock);
>> + if (!locked)
>> + mutex_lock(&kvm->lock);
>
> Hmm, not a fan of passing this variable around. How about this instead
> then (untested):
Yes, I like that version more.
And if we now move the calls to __kvm_vgic_destroy() into vgic-init.c
(as in Marc's first patch, but just before dropping the lock), we don't
even need to export __kvm_vgic_destroy(), right?
Cheers,
Andre.
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 5114391..a25806b 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -264,19 +264,16 @@ int vgic_init(struct kvm *kvm)
> return ret;
> }
>
> +/* Must be called with the kvm->lock held */
> static void kvm_vgic_dist_destroy(struct kvm *kvm)
> {
> struct vgic_dist *dist = &kvm->arch.vgic;
>
> - mutex_lock(&kvm->lock);
> -
> dist->ready = false;
> dist->initialized = false;
>
> kfree(dist->spis);
> dist->nr_spis = 0;
> -
> - mutex_unlock(&kvm->lock);
> }
>
> void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
> @@ -286,7 +283,7 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
> INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> }
>
> -void kvm_vgic_destroy(struct kvm *kvm)
> +void __kvm_vgic_destroy(struct kvm *kvm)
> {
> struct kvm_vcpu *vcpu;
> int i;
> @@ -297,6 +294,13 @@ void kvm_vgic_destroy(struct kvm *kvm)
> kvm_vgic_vcpu_destroy(vcpu);
> }
>
> +void kvm_vgic_destroy(struct kvm *kvm)
> +{
> + mutex_lock(&kvm->lock);
> + __kvm_vgic_destroy(kvm);
> + mutex_unlock(&kvm->lock);
> +}
> +
> /**
> * vgic_lazy_init: Lazy init is only allowed if the GIC exposed to the guest
> * is a GICv2. A GICv3 must be explicitly initialized by the guest using the
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 9bab867..c6f7ec7 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -294,7 +294,7 @@ int vgic_v2_map_resources(struct kvm *kvm)
>
> out:
> if (ret)
> - kvm_vgic_destroy(kvm);
> + __kvm_vgic_destroy(kvm);
> return ret;
> }
>
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 5c9f974..f1c7819 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -303,7 +303,7 @@ int vgic_v3_map_resources(struct kvm *kvm)
>
> out:
> if (ret)
> - kvm_vgic_destroy(kvm);
> + __kvm_vgic_destroy(kvm);
> return ret;
> }
>
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 859f65c..74a0bbb 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -37,6 +37,8 @@ struct vgic_vmcr {
> u32 pmr;
> };
>
> +void __kvm_vgic_destroy(struct kvm *kvm);
> +
> struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> u32 intid);
> void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
>
>
> Thanks,
> -Christoffer
>
^ permalink raw reply
* kvm: deadlock in kvm_vgic_map_resources
From: Marc Zyngier @ 2017-01-12 10:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170112104253.GB13547@cbox>
On 12/01/17 10:42, Christoffer Dall wrote:
> On Thu, Jan 12, 2017 at 10:30:39AM +0000, Marc Zyngier wrote:
>> On 12/01/17 09:55, Andre Przywara wrote:
>>> Hi,
>>>
>>> On 12/01/17 09:32, Marc Zyngier wrote:
>>>> Hi Dmitry,
>>>>
>>>> On 11/01/17 19:01, Dmitry Vyukov wrote:
>>>>> Hello,
>>>>>
>>>>> While running syzkaller fuzzer I've got the following deadlock.
>>>>> On commit 9c763584b7c8911106bb77af7e648bef09af9d80.
>>>>>
>>>>>
>>>>> =============================================
>>>>> [ INFO: possible recursive locking detected ]
>>>>> 4.9.0-rc6-xc2-00056-g08372dd4b91d-dirty #50 Not tainted
>>>>> ---------------------------------------------
>>>>> syz-executor/20805 is trying to acquire lock:
>>>>> (
>>>>> &kvm->lock
>>>>> ){+.+.+.}
>>>>> , at:
>>>>> [< inline >] kvm_vgic_dist_destroy
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:271
>>>>> [<ffff2000080ea4bc>] kvm_vgic_destroy+0x34/0x250
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:294
>>>>> but task is already holding lock:
>>>>> (&kvm->lock){+.+.+.}, at:
>>>>> [<ffff2000080ea7e4>] kvm_vgic_map_resources+0x2c/0x108
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:343
>>>>> other info that might help us debug this:
>>>>> Possible unsafe locking scenario:
>>>>> CPU0
>>>>> ----
>>>>> lock(&kvm->lock);
>>>>> lock(&kvm->lock);
>>>>> *** DEADLOCK ***
>>>>> May be due to missing lock nesting notation
>>>>> 2 locks held by syz-executor/20805:
>>>>> #0:(&vcpu->mutex){+.+.+.}, at:
>>>>> [<ffff2000080bcc30>] vcpu_load+0x28/0x1d0
>>>>> arch/arm64/kvm/../../../virt/kvm/kvm_main.c:143
>>>>> #1:(&kvm->lock){+.+.+.}, at:
>>>>> [<ffff2000080ea7e4>] kvm_vgic_map_resources+0x2c/0x108
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:343
>>>>> stack backtrace:
>>>>> CPU: 2 PID: 20805 Comm: syz-executor Not tainted
>>>>> 4.9.0-rc6-xc2-00056-g08372dd4b91d-dirty #50
>>>>> Hardware name: Hardkernel ODROID-C2 (DT)
>>>>> Call trace:
>>>>> [<ffff200008090560>] dump_backtrace+0x0/0x3c8 arch/arm64/kernel/traps.c:69
>>>>> [<ffff200008090948>] show_stack+0x20/0x30 arch/arm64/kernel/traps.c:219
>>>>> [< inline >] __dump_stack lib/dump_stack.c:15
>>>>> [<ffff200008895840>] dump_stack+0x100/0x150 lib/dump_stack.c:51
>>>>> [< inline >] print_deadlock_bug kernel/locking/lockdep.c:1728
>>>>> [< inline >] check_deadlock kernel/locking/lockdep.c:1772
>>>>> [< inline >] validate_chain kernel/locking/lockdep.c:2250
>>>>> [<ffff2000081c8718>] __lock_acquire+0x1938/0x3440 kernel/locking/lockdep.c:3335
>>>>> [<ffff2000081caa84>] lock_acquire+0xdc/0x1d8 kernel/locking/lockdep.c:3746
>>>>> [< inline >] __mutex_lock_common kernel/locking/mutex.c:521
>>>>> [<ffff200009700004>] mutex_lock_nested+0xdc/0x7b8 kernel/locking/mutex.c:621
>>>>> [< inline >] kvm_vgic_dist_destroy
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:271
>>>>> [<ffff2000080ea4bc>] kvm_vgic_destroy+0x34/0x250
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:294
>>>>> [<ffff2000080ec290>] vgic_v2_map_resources+0x218/0x430
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-v2.c:295
>>>>> [<ffff2000080ea884>] kvm_vgic_map_resources+0xcc/0x108
>>>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:348
>>>>> [< inline >] kvm_vcpu_first_run_init
>>>>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:505
>>>>> [<ffff2000080d2768>] kvm_arch_vcpu_ioctl_run+0xab8/0xce0
>>>>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:591
>>>>> [<ffff2000080c1fec>] kvm_vcpu_ioctl+0x434/0xc08
>>>>> arch/arm64/kvm/../../../virt/kvm/kvm_main.c:2557
>>>>> [< inline >] vfs_ioctl fs/ioctl.c:43
>>>>> [<ffff200008450c38>] do_vfs_ioctl+0x128/0xfc0 fs/ioctl.c:679
>>>>> [< inline >] SYSC_ioctl fs/ioctl.c:694
>>>>> [<ffff200008451b78>] SyS_ioctl+0xa8/0xb8 fs/ioctl.c:685
>>>>> [<ffff200008083ef0>] el0_svc_naked+0x24/0x28 arch/arm64/kernel/entry.S:755
>>>>
>>>> Nice catch, and many thanks for reporting this.
>>>>
>>>> The bug is fairly obvious. Christoffer, what do you think? I don't think
>>>> we need to hold the kvm->lock all the way, but I'd like another pair of
>>>> eyes (the coffee machine is out of order again, and tea doesn't cut it).
>>>>
>>>> Thanks,
>>>>
>>>> M.
>>>>
>>>> From 93f80b20fb9351a49ee8b74eed3fc59c84651371 Mon Sep 17 00:00:00 2001
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>> Date: Thu, 12 Jan 2017 09:21:56 +0000
>>>> Subject: [PATCH] KVM: arm/arm64: vgic: Fix deadlock on error handling
>>>>
>>>> Dmitry Vyukov reported that the syzkaller fuzzer triggered a
>>>> deadlock in the vgic setup code when an error was detected, as
>>>> the cleanup code tries to take a lock that is already held by
>>>> the setup code.
>>>>
>>>> The fix is pretty obvious: move the cleaup call after having
>>>> dropped the lock, since not much can happen at that point.
>>> ^^^^^^^^
>>> Is that really true? If for instance the calls to
>>> vgic_register_dist_iodev() or kvm_phys_addr_ioremap() in
>>> vgic_v2_map_resources() fail, we leave the function with a half
>>> initialized VGIC (because vgic_init() succeeded).
>>
>> But we only set dist->ready to true when everything went OK. How is
>> that an issue?
>>
>>> Dropping the lock at
>>> this point without having the GIC cleaned up before sounds a bit
>>> suspicious (I may be wrong on this, though).
>>
>> Thinking of it, that may open a race with vgic init call, leading to
>> leaking distributor memory.
>>
>>>
>>> Can't we just document that kvm_vgic_destroy() needs to be called with
>>> the kvm->lock held and take the lock around the only other caller
>>> (kvm_arch_destroy_vm() in arch/arm/kvm/arm.c)?
>>> We can then keep holding the lock in the map_resources calls.
>>> Though we might still move the calls to kvm_vgic_destroy() into the
>>> wrapper function as a cleanup (as shown below), just before dropping the
>>> lock.
>>
>> I'd rather keep the changes limited to the vgic code, and save myself
>> having to document more locking (we already have our fair share here).
>> How about this (untested):
>>
>> From 24dc3f5750da20d89e0ce9b7855d125d0100bee8 Mon Sep 17 00:00:00 2001
>> From: Marc Zyngier <marc.zyngier@arm.com>
>> Date: Thu, 12 Jan 2017 09:21:56 +0000
>> Subject: [PATCH] KVM: arm/arm64: vgic: Fix deadlock on error handling
>>
>> Dmitry Vyukov reported that the syzkaller fuzzer triggered a
>> deadlock in the vgic setup code when an error was detected, as
>> the cleanup code tries to take a lock that is already held by
>> the setup code.
>>
>> The fix is to avoid retaking the lock when cleaning up, by
>> telling the cleanup function that we already hold it.
>>
>> Cc: stable at vger.kernel.org
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>> virt/kvm/arm/vgic/vgic-init.c | 21 ++++++++++++++++-----
>> virt/kvm/arm/vgic/vgic-v2.c | 2 --
>> virt/kvm/arm/vgic/vgic-v3.c | 2 --
>> 3 files changed, 16 insertions(+), 9 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
>> index 5114391..30d74e2 100644
>> --- a/virt/kvm/arm/vgic/vgic-init.c
>> +++ b/virt/kvm/arm/vgic/vgic-init.c
>> @@ -264,11 +264,12 @@ int vgic_init(struct kvm *kvm)
>> return ret;
>> }
>>
>> -static void kvm_vgic_dist_destroy(struct kvm *kvm)
>> +static void kvm_vgic_dist_destroy(struct kvm *kvm, bool locked)
>> {
>> struct vgic_dist *dist = &kvm->arch.vgic;
>>
>> - mutex_lock(&kvm->lock);
>> + if (!locked)
>> + mutex_lock(&kvm->lock);
>
> Hmm, not a fan of passing this variable around. How about this instead
> then (untested):
>
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 5114391..a25806b 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -264,19 +264,16 @@ int vgic_init(struct kvm *kvm)
> return ret;
> }
>
> +/* Must be called with the kvm->lock held */
> static void kvm_vgic_dist_destroy(struct kvm *kvm)
> {
> struct vgic_dist *dist = &kvm->arch.vgic;
>
> - mutex_lock(&kvm->lock);
> -
> dist->ready = false;
> dist->initialized = false;
>
> kfree(dist->spis);
> dist->nr_spis = 0;
> -
> - mutex_unlock(&kvm->lock);
> }
>
> void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
> @@ -286,7 +283,7 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
> INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> }
>
> -void kvm_vgic_destroy(struct kvm *kvm)
> +void __kvm_vgic_destroy(struct kvm *kvm)
> {
> struct kvm_vcpu *vcpu;
> int i;
> @@ -297,6 +294,13 @@ void kvm_vgic_destroy(struct kvm *kvm)
> kvm_vgic_vcpu_destroy(vcpu);
> }
>
> +void kvm_vgic_destroy(struct kvm *kvm)
> +{
> + mutex_lock(&kvm->lock);
> + __kvm_vgic_destroy(kvm);
> + mutex_unlock(&kvm->lock);
> +}
> +
I initially wrote that exactly, but ended up deciding against as it
changes the locking more than strictly necessary. On the other hand, I
think this looks better, so if everyone agrees I'll take that.
> /**
> * vgic_lazy_init: Lazy init is only allowed if the GIC exposed to the guest
> * is a GICv2. A GICv3 must be explicitly initialized by the guest using the
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 9bab867..c6f7ec7 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -294,7 +294,7 @@ int vgic_v2_map_resources(struct kvm *kvm)
>
> out:
> if (ret)
> - kvm_vgic_destroy(kvm);
> + __kvm_vgic_destroy(kvm);
> return ret;
> }
>
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 5c9f974..f1c7819 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -303,7 +303,7 @@ int vgic_v3_map_resources(struct kvm *kvm)
>
> out:
> if (ret)
> - kvm_vgic_destroy(kvm);
> + __kvm_vgic_destroy(kvm);
I'm still keen on factoring the destroy calls in the calling function.
Is there any reason why we wouldn't do it?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* kvm: deadlock in kvm_vgic_map_resources
From: Christoffer Dall @ 2017-01-12 10:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0994d5a9-d9f4-7b80-4b16-1797c093edb5@arm.com>
On Thu, Jan 12, 2017 at 10:30:39AM +0000, Marc Zyngier wrote:
> On 12/01/17 09:55, Andre Przywara wrote:
> > Hi,
> >
> > On 12/01/17 09:32, Marc Zyngier wrote:
> >> Hi Dmitry,
> >>
> >> On 11/01/17 19:01, Dmitry Vyukov wrote:
> >>> Hello,
> >>>
> >>> While running syzkaller fuzzer I've got the following deadlock.
> >>> On commit 9c763584b7c8911106bb77af7e648bef09af9d80.
> >>>
> >>>
> >>> =============================================
> >>> [ INFO: possible recursive locking detected ]
> >>> 4.9.0-rc6-xc2-00056-g08372dd4b91d-dirty #50 Not tainted
> >>> ---------------------------------------------
> >>> syz-executor/20805 is trying to acquire lock:
> >>> (
> >>> &kvm->lock
> >>> ){+.+.+.}
> >>> , at:
> >>> [< inline >] kvm_vgic_dist_destroy
> >>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:271
> >>> [<ffff2000080ea4bc>] kvm_vgic_destroy+0x34/0x250
> >>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:294
> >>> but task is already holding lock:
> >>> (&kvm->lock){+.+.+.}, at:
> >>> [<ffff2000080ea7e4>] kvm_vgic_map_resources+0x2c/0x108
> >>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:343
> >>> other info that might help us debug this:
> >>> Possible unsafe locking scenario:
> >>> CPU0
> >>> ----
> >>> lock(&kvm->lock);
> >>> lock(&kvm->lock);
> >>> *** DEADLOCK ***
> >>> May be due to missing lock nesting notation
> >>> 2 locks held by syz-executor/20805:
> >>> #0:(&vcpu->mutex){+.+.+.}, at:
> >>> [<ffff2000080bcc30>] vcpu_load+0x28/0x1d0
> >>> arch/arm64/kvm/../../../virt/kvm/kvm_main.c:143
> >>> #1:(&kvm->lock){+.+.+.}, at:
> >>> [<ffff2000080ea7e4>] kvm_vgic_map_resources+0x2c/0x108
> >>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:343
> >>> stack backtrace:
> >>> CPU: 2 PID: 20805 Comm: syz-executor Not tainted
> >>> 4.9.0-rc6-xc2-00056-g08372dd4b91d-dirty #50
> >>> Hardware name: Hardkernel ODROID-C2 (DT)
> >>> Call trace:
> >>> [<ffff200008090560>] dump_backtrace+0x0/0x3c8 arch/arm64/kernel/traps.c:69
> >>> [<ffff200008090948>] show_stack+0x20/0x30 arch/arm64/kernel/traps.c:219
> >>> [< inline >] __dump_stack lib/dump_stack.c:15
> >>> [<ffff200008895840>] dump_stack+0x100/0x150 lib/dump_stack.c:51
> >>> [< inline >] print_deadlock_bug kernel/locking/lockdep.c:1728
> >>> [< inline >] check_deadlock kernel/locking/lockdep.c:1772
> >>> [< inline >] validate_chain kernel/locking/lockdep.c:2250
> >>> [<ffff2000081c8718>] __lock_acquire+0x1938/0x3440 kernel/locking/lockdep.c:3335
> >>> [<ffff2000081caa84>] lock_acquire+0xdc/0x1d8 kernel/locking/lockdep.c:3746
> >>> [< inline >] __mutex_lock_common kernel/locking/mutex.c:521
> >>> [<ffff200009700004>] mutex_lock_nested+0xdc/0x7b8 kernel/locking/mutex.c:621
> >>> [< inline >] kvm_vgic_dist_destroy
> >>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:271
> >>> [<ffff2000080ea4bc>] kvm_vgic_destroy+0x34/0x250
> >>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:294
> >>> [<ffff2000080ec290>] vgic_v2_map_resources+0x218/0x430
> >>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-v2.c:295
> >>> [<ffff2000080ea884>] kvm_vgic_map_resources+0xcc/0x108
> >>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:348
> >>> [< inline >] kvm_vcpu_first_run_init
> >>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:505
> >>> [<ffff2000080d2768>] kvm_arch_vcpu_ioctl_run+0xab8/0xce0
> >>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:591
> >>> [<ffff2000080c1fec>] kvm_vcpu_ioctl+0x434/0xc08
> >>> arch/arm64/kvm/../../../virt/kvm/kvm_main.c:2557
> >>> [< inline >] vfs_ioctl fs/ioctl.c:43
> >>> [<ffff200008450c38>] do_vfs_ioctl+0x128/0xfc0 fs/ioctl.c:679
> >>> [< inline >] SYSC_ioctl fs/ioctl.c:694
> >>> [<ffff200008451b78>] SyS_ioctl+0xa8/0xb8 fs/ioctl.c:685
> >>> [<ffff200008083ef0>] el0_svc_naked+0x24/0x28 arch/arm64/kernel/entry.S:755
> >>
> >> Nice catch, and many thanks for reporting this.
> >>
> >> The bug is fairly obvious. Christoffer, what do you think? I don't think
> >> we need to hold the kvm->lock all the way, but I'd like another pair of
> >> eyes (the coffee machine is out of order again, and tea doesn't cut it).
> >>
> >> Thanks,
> >>
> >> M.
> >>
> >> From 93f80b20fb9351a49ee8b74eed3fc59c84651371 Mon Sep 17 00:00:00 2001
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >> Date: Thu, 12 Jan 2017 09:21:56 +0000
> >> Subject: [PATCH] KVM: arm/arm64: vgic: Fix deadlock on error handling
> >>
> >> Dmitry Vyukov reported that the syzkaller fuzzer triggered a
> >> deadlock in the vgic setup code when an error was detected, as
> >> the cleanup code tries to take a lock that is already held by
> >> the setup code.
> >>
> >> The fix is pretty obvious: move the cleaup call after having
> >> dropped the lock, since not much can happen at that point.
> > ^^^^^^^^
> > Is that really true? If for instance the calls to
> > vgic_register_dist_iodev() or kvm_phys_addr_ioremap() in
> > vgic_v2_map_resources() fail, we leave the function with a half
> > initialized VGIC (because vgic_init() succeeded).
>
> But we only set dist->ready to true when everything went OK. How is
> that an issue?
>
> > Dropping the lock at
> > this point without having the GIC cleaned up before sounds a bit
> > suspicious (I may be wrong on this, though).
>
> Thinking of it, that may open a race with vgic init call, leading to
> leaking distributor memory.
>
> >
> > Can't we just document that kvm_vgic_destroy() needs to be called with
> > the kvm->lock held and take the lock around the only other caller
> > (kvm_arch_destroy_vm() in arch/arm/kvm/arm.c)?
> > We can then keep holding the lock in the map_resources calls.
> > Though we might still move the calls to kvm_vgic_destroy() into the
> > wrapper function as a cleanup (as shown below), just before dropping the
> > lock.
>
> I'd rather keep the changes limited to the vgic code, and save myself
> having to document more locking (we already have our fair share here).
> How about this (untested):
>
> From 24dc3f5750da20d89e0ce9b7855d125d0100bee8 Mon Sep 17 00:00:00 2001
> From: Marc Zyngier <marc.zyngier@arm.com>
> Date: Thu, 12 Jan 2017 09:21:56 +0000
> Subject: [PATCH] KVM: arm/arm64: vgic: Fix deadlock on error handling
>
> Dmitry Vyukov reported that the syzkaller fuzzer triggered a
> deadlock in the vgic setup code when an error was detected, as
> the cleanup code tries to take a lock that is already held by
> the setup code.
>
> The fix is to avoid retaking the lock when cleaning up, by
> telling the cleanup function that we already hold it.
>
> Cc: stable at vger.kernel.org
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> virt/kvm/arm/vgic/vgic-init.c | 21 ++++++++++++++++-----
> virt/kvm/arm/vgic/vgic-v2.c | 2 --
> virt/kvm/arm/vgic/vgic-v3.c | 2 --
> 3 files changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 5114391..30d74e2 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -264,11 +264,12 @@ int vgic_init(struct kvm *kvm)
> return ret;
> }
>
> -static void kvm_vgic_dist_destroy(struct kvm *kvm)
> +static void kvm_vgic_dist_destroy(struct kvm *kvm, bool locked)
> {
> struct vgic_dist *dist = &kvm->arch.vgic;
>
> - mutex_lock(&kvm->lock);
> + if (!locked)
> + mutex_lock(&kvm->lock);
Hmm, not a fan of passing this variable around. How about this instead
then (untested):
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 5114391..a25806b 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -264,19 +264,16 @@ int vgic_init(struct kvm *kvm)
return ret;
}
+/* Must be called with the kvm->lock held */
static void kvm_vgic_dist_destroy(struct kvm *kvm)
{
struct vgic_dist *dist = &kvm->arch.vgic;
- mutex_lock(&kvm->lock);
-
dist->ready = false;
dist->initialized = false;
kfree(dist->spis);
dist->nr_spis = 0;
-
- mutex_unlock(&kvm->lock);
}
void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
@@ -286,7 +283,7 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
}
-void kvm_vgic_destroy(struct kvm *kvm)
+void __kvm_vgic_destroy(struct kvm *kvm)
{
struct kvm_vcpu *vcpu;
int i;
@@ -297,6 +294,13 @@ void kvm_vgic_destroy(struct kvm *kvm)
kvm_vgic_vcpu_destroy(vcpu);
}
+void kvm_vgic_destroy(struct kvm *kvm)
+{
+ mutex_lock(&kvm->lock);
+ __kvm_vgic_destroy(kvm);
+ mutex_unlock(&kvm->lock);
+}
+
/**
* vgic_lazy_init: Lazy init is only allowed if the GIC exposed to the guest
* is a GICv2. A GICv3 must be explicitly initialized by the guest using the
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 9bab867..c6f7ec7 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -294,7 +294,7 @@ int vgic_v2_map_resources(struct kvm *kvm)
out:
if (ret)
- kvm_vgic_destroy(kvm);
+ __kvm_vgic_destroy(kvm);
return ret;
}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 5c9f974..f1c7819 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -303,7 +303,7 @@ int vgic_v3_map_resources(struct kvm *kvm)
out:
if (ret)
- kvm_vgic_destroy(kvm);
+ __kvm_vgic_destroy(kvm);
return ret;
}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 859f65c..74a0bbb 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -37,6 +37,8 @@ struct vgic_vmcr {
u32 pmr;
};
+void __kvm_vgic_destroy(struct kvm *kvm);
+
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
u32 intid);
void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
Thanks,
-Christoffer
^ permalink raw reply related
* [PATCH 1/2] mmc: mediatek: Use data tune for CMD line tune
From: Ulf Hansson @ 2017-01-12 10:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484215490-7494-2-git-send-email-yong.mao@mediatek.com>
On 12 January 2017 at 11:04, Yong Mao <yong.mao@mediatek.com> wrote:
> From: yong mao <yong.mao@mediatek.com>
>
> CMD response CRC error may cause cannot boot up
> Change to use data tune for CMD line
> Separate cmd internal delay for HS200/HS400 mode
Please try to work a little bit on improving the change log. Moreover
as this is a fix for a regression (it seems like so?), please try to
make that clear.
>
> Signed-off-by: Yong Mao <yong.mao@mediatek.com>
> Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
> ---
> arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 3 +
Changes to the DTS files should be a separate change. Please split it
into its own patch.
> drivers/mmc/host/mtk-sd.c | 169 +++++++++++++++++++++++----
> 2 files changed, 149 insertions(+), 23 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
> index 0ecaad4..29c3100 100644
> --- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
> +++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
> @@ -134,6 +134,9 @@
> bus-width = <8>;
> max-frequency = <50000000>;
> cap-mmc-highspeed;
> + hs200-cmd-int-delay = <26>;
> + hs400-cmd-int-delay = <14>;
> + cmd-resp-sel = <0>; /* 0: rising, 1: falling */
> vmmc-supply = <&mt6397_vemc_3v3_reg>;
> vqmmc-supply = <&mt6397_vio18_reg>;
> non-removable;
> diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
> index 80ba034..93eb395 100644
> --- a/drivers/mmc/host/mtk-sd.c
> +++ b/drivers/mmc/host/mtk-sd.c
> @@ -75,6 +75,7 @@
> #define MSDC_PATCH_BIT1 0xb4
> #define MSDC_PAD_TUNE 0xec
> #define PAD_DS_TUNE 0x188
> +#define PAD_CMD_TUNE 0x18c
> #define EMMC50_CFG0 0x208
>
> /*--------------------------------------------------------------------------*/
> @@ -210,12 +211,17 @@
> #define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */
> #define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */
>
> -#define MSDC_PAD_TUNE_DATRRDLY (0x1f << 8) /* RW */
> -#define MSDC_PAD_TUNE_CMDRDLY (0x1f << 16) /* RW */
> +#define MSDC_PAD_TUNE_DATWRDLY (0x1f << 0) /* RW */
> +#define MSDC_PAD_TUNE_DATRRDLY (0x1f << 8) /* RW */
> +#define MSDC_PAD_TUNE_CMDRDLY (0x1f << 16) /* RW */
> +#define MSDC_PAD_TUNE_CMDRRDLY (0x1f << 22) /* RW */
Is there a white space change somewhere here? I don't see any changes
to MSDC_PAD_TUNE_DATRRDLY and MSDC_PAD_TUNE_CMDRDLY.
> +#define MSDC_PAD_TUNE_CLKTDLY (0x1f << 27) /* RW */
>
> -#define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */
> -#define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */
> -#define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */
> +#define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */
> +#define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */
> +#define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */
> +
Ditto.
> +#define PAD_CMD_TUNE_RX_DLY3 (0x1f << 1) /* RW */
>
> #define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0) /* RW */
> #define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3) /* RW */
> @@ -236,7 +242,9 @@
> #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */
> #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */
>
> -#define PAD_DELAY_MAX 32 /* PAD delay cells */
> +#define PAD_DELAY_MAX 32 /* PAD delay cells */
Ditto.
> +#define ENOUGH_MARGIN_MIN 12 /* Enough Margin */
> +#define PREFER_START_POS_MAX 4 /* Prefer start position */
> /*--------------------------------------------------------------------------*/
> /* Descriptor Structure */
> /*--------------------------------------------------------------------------*/
> @@ -284,12 +292,14 @@ struct msdc_save_para {
> u32 patch_bit0;
> u32 patch_bit1;
> u32 pad_ds_tune;
> + u32 pad_cmd_tune;
> u32 emmc50_cfg0;
> };
>
> struct msdc_tune_para {
> u32 iocon;
> u32 pad_tune;
> + u32 pad_cmd_tune;
> };
>
> struct msdc_delay_phase {
> @@ -331,6 +341,9 @@ struct msdc_host {
> unsigned char timing;
> bool vqmmc_enabled;
> u32 hs400_ds_delay;
> + u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */
> + u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */
> + u32 hs200_cmd_resp_sel; /* cmd response sample selection */
> bool hs400_mode; /* current eMMC will run at hs400 mode */
> struct msdc_save_para save_para; /* used when gate HCLK */
> struct msdc_tune_para def_tune_para; /* default tune setting */
> @@ -596,12 +609,21 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
> */
> if (host->sclk <= 52000000) {
> writel(host->def_tune_para.iocon, host->base + MSDC_IOCON);
> - writel(host->def_tune_para.pad_tune, host->base + MSDC_PAD_TUNE);
> + writel(host->def_tune_para.pad_tune,
> + host->base + MSDC_PAD_TUNE);
Please don't change code just because you feel like doing it. This is
a completely unessarry change and it makes it harder for me to review.
Can you go thorugh the complete patch and make sure to undo all
similar changes, there are more of them.
> } else {
> - writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON);
> - writel(host->saved_tune_para.pad_tune, host->base + MSDC_PAD_TUNE);
> + writel(host->saved_tune_para.iocon,
> + host->base + MSDC_IOCON);
> + writel(host->saved_tune_para.pad_tune,
> + host->base + MSDC_PAD_TUNE);
> + writel(host->saved_tune_para.pad_cmd_tune,
> + host->base + PAD_CMD_TUNE);
> }
>
> + if (timing == MMC_TIMING_MMC_HS400)
> + sdr_set_field(host->base + PAD_CMD_TUNE,
> + MSDC_PAD_TUNE_CMDRRDLY,
> + host->hs400_cmd_int_delay);
> dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing);
> }
>
> @@ -1302,7 +1324,8 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
> len_final = len;
> }
> start += len ? len : 1;
> - if (len >= 8 && start_final < 4)
> + if (len >= ENOUGH_MARGIN_MIN &&
> + start_final < PREFER_START_POS_MAX)
> break;
> }
>
> @@ -1325,48 +1348,128 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
> struct msdc_host *host = mmc_priv(mmc);
> u32 rise_delay = 0, fall_delay = 0;
> struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
> + struct msdc_delay_phase internal_delay_phase;
> u8 final_delay, final_maxlen;
> + u32 internal_delay = 0;
> int cmd_err;
> - int i;
> + int i, j;
>
> + if (mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
> + mmc->ios.timing == MMC_TIMING_UHS_SDR104)
> + sdr_set_field(host->base + MSDC_PAD_TUNE,
> + MSDC_PAD_TUNE_CMDRRDLY,
> + host->hs200_cmd_int_delay);
> sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
> for (i = 0 ; i < PAD_DELAY_MAX; i++) {
> sdr_set_field(host->base + MSDC_PAD_TUNE,
> MSDC_PAD_TUNE_CMDRDLY, i);
> - mmc_send_tuning(mmc, opcode, &cmd_err);
> - if (!cmd_err)
> - rise_delay |= (1 << i);
> + for (j = 0; j < 3; j++) {
Any reason to why looping three times makes sense? Maybe add a comment?
> + mmc_send_tuning(mmc, opcode, &cmd_err);
> + if (!cmd_err) {
> + rise_delay |= (1 << i);
> + } else {
> + rise_delay &= ~(1 << i);
> + break;
> + }
> + }
> }
> final_rise_delay = get_best_delay(host, rise_delay);
> /* if rising edge has enough margin, then do not scan falling edge */
> - if (final_rise_delay.maxlen >= 10 ||
> - (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
> + if (final_rise_delay.maxlen >= ENOUGH_MARGIN_MIN &&
> + final_rise_delay.start < PREFER_START_POS_MAX)
This looks like clean-ups, as you are converting from magic numbers to
defines. Please make this kind of changes separately.
> goto skip_fall;
>
> sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
> for (i = 0; i < PAD_DELAY_MAX; i++) {
> sdr_set_field(host->base + MSDC_PAD_TUNE,
> MSDC_PAD_TUNE_CMDRDLY, i);
> - mmc_send_tuning(mmc, opcode, &cmd_err);
> - if (!cmd_err)
> - fall_delay |= (1 << i);
> + for (j = 0; j < 3; j++) {
3?
> + mmc_send_tuning(mmc, opcode, &cmd_err);
> + if (!cmd_err) {
> + fall_delay |= (1 << i);
> + } else {
> + fall_delay &= ~(1 << i);
> + break;
> + };
> + }
> }
> final_fall_delay = get_best_delay(host, fall_delay);
>
> skip_fall:
> final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
> + if (final_fall_delay.maxlen >= ENOUGH_MARGIN_MIN &&
> + final_fall_delay.start < PREFER_START_POS_MAX)
> + final_maxlen = final_fall_delay.maxlen;
> if (final_maxlen == final_rise_delay.maxlen) {
> sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
> - sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
> + sdr_set_field(host->base + MSDC_PAD_TUNE,
> + MSDC_PAD_TUNE_CMDRDLY,
> final_rise_delay.final_phase);
> final_delay = final_rise_delay.final_phase;
> } else {
> sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
> - sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
> + sdr_set_field(host->base + MSDC_PAD_TUNE,
> + MSDC_PAD_TUNE_CMDRDLY,
> final_fall_delay.final_phase);
> final_delay = final_fall_delay.final_phase;
> }
> + if (host->hs200_cmd_int_delay)
> + goto skip_internal;
>
> + for (i = 0; i < PAD_DELAY_MAX; i++) {
> + sdr_set_field(host->base + MSDC_PAD_TUNE,
> + MSDC_PAD_TUNE_CMDRRDLY, i);
> + mmc_send_tuning(mmc, opcode, &cmd_err);
> + if (!cmd_err)
> + internal_delay |= (1 << i);
> + }
> + dev_info(host->dev, "Final internal delay: 0x%x\n", internal_delay);
I don't think dev_info() is what you want, right? Perhaps dev_dbg(),
anything at all.
> + internal_delay_phase = get_best_delay(host, internal_delay);
> + sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY,
> + internal_delay_phase.final_phase);
> +skip_internal:
> + dev_info(host->dev, "Final cmd pad delay: %x\n", final_delay);
I don't think dev_info() is what you want, right? Perhaps dev_dbg(),
anything at all.
> + return final_delay == 0xff ? -EIO : 0;
> +}
> +
> +static int hs400_tune_response(struct mmc_host *mmc, u32 opcode)
> +{
> + struct msdc_host *host = mmc_priv(mmc);
> + u32 cmd_delay = 0;
> + struct msdc_delay_phase final_cmd_delay = { 0,};
> + u8 final_delay;
> + int cmd_err;
> + int i, j;
> +
> + /* select EMMC50 PAD CMD tune */
> + sdr_set_bits(host->base + PAD_CMD_TUNE, BIT(0));
> +
> + if (mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
> + mmc->ios.timing == MMC_TIMING_UHS_SDR104)
> + sdr_set_field(host->base + MSDC_PAD_TUNE,
> + MSDC_PAD_TUNE_CMDRRDLY,
> + host->hs200_cmd_int_delay);
> + sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL,
> + host->hs200_cmd_resp_sel);
> + for (i = 0 ; i < PAD_DELAY_MAX; i++) {
> + sdr_set_field(host->base + PAD_CMD_TUNE,
> + PAD_CMD_TUNE_RX_DLY3, i);
> + for (j = 0; j < 3; j++) {
3?
> + mmc_send_tuning(mmc, opcode, &cmd_err);
> + if (!cmd_err) {
> + cmd_delay |= (1 << i);
> + } else {
> + cmd_delay &= ~(1 << i);
> + break;
> + }
> + }
> + }
> + final_cmd_delay = get_best_delay(host, cmd_delay);
> + sdr_set_field(host->base + PAD_CMD_TUNE, PAD_CMD_TUNE_RX_DLY3,
> + final_cmd_delay.final_phase);
> + final_delay = final_cmd_delay.final_phase;
> +
> + dev_info(host->dev, "Final cmd pad delay: %x\n", final_delay);
dev_info() -> dev_dbg() or remove it.
> return final_delay == 0xff ? -EIO : 0;
> }
>
> @@ -1389,7 +1492,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
> }
> final_rise_delay = get_best_delay(host, rise_delay);
> /* if rising edge has enough margin, then do not scan falling edge */
> - if (final_rise_delay.maxlen >= 10 ||
> + if (final_rise_delay.maxlen >= ENOUGH_MARGIN_MIN ||
Clean up. Move to separate change.
> (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
> goto skip_fall;
>
> @@ -1422,6 +1525,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
> final_delay = final_fall_delay.final_phase;
> }
>
> + dev_info(host->dev, "Final data pad delay: %x\n", final_delay);
dev_info() -> dev_dbg() or remove it.
> return final_delay == 0xff ? -EIO : 0;
> }
>
> @@ -1430,10 +1534,13 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
> struct msdc_host *host = mmc_priv(mmc);
> int ret;
>
> + if (host->hs400_mode)
> + ret = hs400_tune_response(mmc, opcode);
> + else
> ret = msdc_tune_response(mmc, opcode);
Because of the new else clause, seems like above needs an intendation.
> if (ret == -EIO) {
> dev_err(host->dev, "Tune response fail!\n");
> - return ret;
> + goto out;
Not needed, remove the label and this change.
> }
> if (host->hs400_mode == false) {
> ret = msdc_tune_data(mmc, opcode);
> @@ -1443,6 +1550,8 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
>
> host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
> host->saved_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
> + host->saved_tune_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE);
> +out:
> return ret;
> }
>
> @@ -1553,6 +1662,18 @@ static int msdc_drv_probe(struct platform_device *pdev)
> dev_dbg(&pdev->dev, "hs400-ds-delay: %x\n",
> host->hs400_ds_delay);
>
> + if (!of_property_read_u32(pdev->dev.of_node, "hs200-cmd-int-delay",
> + &host->hs200_cmd_int_delay))
> + dev_dbg(&pdev->dev, "host->hs200-cmd-int-delay: %x\n",
> + host->hs200_cmd_int_delay);
> + if (!of_property_read_u32(pdev->dev.of_node, "hs400-cmd-int-delay",
> + &host->hs400_cmd_int_delay))
> + dev_dbg(&pdev->dev, "host->hs400-cmd-int-delay: %x\n",
> + host->hs400_cmd_int_delay);
> + if (!of_property_read_u32(pdev->dev.of_node, "cmd-resp-sel",
> + &host->hs200_cmd_resp_sel))
> + dev_dbg(&pdev->dev, "host->hs200_cmd-resp-sel: %x\n",
> + host->hs200_cmd_resp_sel);
I suggest you take the oppotunity to move the MTK DTS parsing into its
own function, include the existing parsing of the "hs400-ds-delay".
This improve the readablitity of the code.
> host->dev = &pdev->dev;
> host->mmc = mmc;
> host->src_clk_freq = clk_get_rate(host->src_clk);
> @@ -1663,6 +1784,7 @@ static void msdc_save_reg(struct msdc_host *host)
> host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
> host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
> host->save_para.pad_ds_tune = readl(host->base + PAD_DS_TUNE);
> + host->save_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE);
> host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0);
> }
>
> @@ -1675,6 +1797,7 @@ static void msdc_restore_reg(struct msdc_host *host)
> writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
> writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
> writel(host->save_para.pad_ds_tune, host->base + PAD_DS_TUNE);
> + writel(host->save_para.pad_cmd_tune, host->base + PAD_CMD_TUNE);
> writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0);
> }
>
> --
> 1.7.9.5
>
Kind regards
Uffe
^ permalink raw reply
* [RFC PATCH v4 0/5] ARM: Fix dma_alloc_coherent() and friends for NOMMU
From: Benjamin Gaignard @ 2017-01-12 10:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <f4d17374-eb46-79f7-e394-cb2739f71ef4@arm.com>
2017-01-11 15:34 GMT+01:00 Vladimir Murzin <vladimir.murzin@arm.com>:
> On 11/01/17 13:17, Benjamin Gaignard wrote:
>> 2017-01-10 15:18 GMT+01:00 Vladimir Murzin <vladimir.murzin@arm.com>:
>>> Hi,
>>>
>>> It seem that addition of cache support for M-class cpus uncovered
>>> latent bug in DMA usage. NOMMU memory model has been treated as being
>>> always consistent; however, for R/M classes of cpu memory can be
>>> covered by MPU which in turn might configure RAM as Normal
>>> i.e. bufferable and cacheable. It breaks dma_alloc_coherent() and
>>> friends, since data can stuck in caches now or be buffered.
>>>
>>> This patch set is trying to address the issue by providing region of
>>> memory suitable for consistent DMA operations. It is supposed that
>>> such region is marked by MPU as non-cacheable. Robin suggested to
>>> advertise such memory as reserved shared-dma-pool, rather then using
>>> homebrew command line option, and extend dma-coherent to provide
>>> default DMA area in the similar way as it is done for CMA (PATCH
>>> 2/5). It allows us to offload all bookkeeping on generic coherent DMA
>>> framework, and it is seems that it might be reused by other
>>> architectures like c6x and blackfin.
>>>
>>> Dedicated DMA region is required for cases other than:
>>> - MMU/MPU is off
>>> - cpu is v7m w/o cache support
>>> - device is coherent
>>>
>>> In case one of the above conditions is true dma operations are forced
>>> to be coherent and wired with dma_noop_ops.
>>>
>>> To make life easier NOMMU dma operations are kept in separate
>>> compilation unit.
>>>
>>> Since the issue was reported in the same time as Benjamin sent his
>>> patch [1] to allow mmap for NOMMU, his case is also addressed in this
>>> series (PATCH 1/5 and PATCH 3/5).
>>>
>>> Thanks!
>>
>> I have tested this v4 on my setup (stm32f4, no cache, no MPU) and unfortunately
>> it doesn't work with my drm/kms driver.
>
> I guess the same is for fbmem, but would be better to have confirmation since
> amba-clcd I use has not been ported to drm/kms (yet), so I can't test.
>
>> I haven't any errors but nothing is displayed unlike what I have when
>> using current dma-mapping
>> code.
>> I guess the issue is coming from dma-noop where __get_free_pages() is
>> used instead of alloc_pages()
>> in dma-mapping.
>
> Unless I've missed something bellow is a call stack for both
>
> #1
> __alloc_simple_buffer
> __dma_alloc_buffer
> alloc_pages
> split_page
> __dma_clear_buffer
> memset
> page_address
>
> #2
> __get_free_pages
> alloc_pages
> page_address
>
> So the difference is that nommu case in dma-mapping.c memzeros memory, handles
> DMA_ATTR_NO_KERNEL_MAPPING and does optimisation of memory usage.
>
> Is something from above critical for your driver?
I have removed all the diff (split_page, __dma_clear_buffer, memset)
from #1 and it is still working.
DMA_ATTR_NO_KERNEL_MAPPING flag is not set when allocating the buffer.
I have investigated more and found that dma-noop doesn't take care of
"dma-ranges" property which is set in DT.
I believed that is the root cause of my problem with your patches.
Benjamin
>
>>
>> Since my hardware doesn't have cache or MPU (and so use dma-noop) I
>> haven't reserved specific memory region.
>> Buffer addresses and vma parameters look correct... What could I have
>> miss here ?
>
> No ideas, sorry...
>
> Cheers
> Vladimir
>
>>
>> Benjamin
>>
>>>
>>> [1] http://www.armlinux.org.uk/developer/patches/viewpatch.php?id=8633/1
>>>
>>> Vladimir Murzin (5):
>>> dma: Add simple dma_noop_mmap
>>> drivers: dma-coherent: Introduce default DMA pool
>>> ARM: NOMMU: Introduce dma operations for noMMU
>>> ARM: NOMMU: Set ARM_DMA_MEM_BUFFERABLE for M-class cpus
>>> ARM: dma-mapping: Remove traces of NOMMU code
>>>
>>> .../bindings/reserved-memory/reserved-memory.txt | 3 +
>>> arch/arm/include/asm/dma-mapping.h | 3 +-
>>> arch/arm/mm/Kconfig | 2 +-
>>> arch/arm/mm/Makefile | 5 +-
>>> arch/arm/mm/dma-mapping-nommu.c | 252 +++++++++++++++++++++
>>> arch/arm/mm/dma-mapping.c | 26 +--
>>> drivers/base/dma-coherent.c | 59 ++++-
>>> lib/dma-noop.c | 21 ++
>>> 8 files changed, 335 insertions(+), 36 deletions(-)
>>> create mode 100644 arch/arm/mm/dma-mapping-nommu.c
>>>
>>> --
>>> 2.0.0
>>>
>>
>>
>>
>
--
Benjamin Gaignard
Graphic Study Group
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* kvm: deadlock in kvm_vgic_map_resources
From: Marc Zyngier @ 2017-01-12 10:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <286255e8-918e-66b5-012f-f347a2ae71cd@arm.com>
On 12/01/17 09:55, Andre Przywara wrote:
> Hi,
>
> On 12/01/17 09:32, Marc Zyngier wrote:
>> Hi Dmitry,
>>
>> On 11/01/17 19:01, Dmitry Vyukov wrote:
>>> Hello,
>>>
>>> While running syzkaller fuzzer I've got the following deadlock.
>>> On commit 9c763584b7c8911106bb77af7e648bef09af9d80.
>>>
>>>
>>> =============================================
>>> [ INFO: possible recursive locking detected ]
>>> 4.9.0-rc6-xc2-00056-g08372dd4b91d-dirty #50 Not tainted
>>> ---------------------------------------------
>>> syz-executor/20805 is trying to acquire lock:
>>> (
>>> &kvm->lock
>>> ){+.+.+.}
>>> , at:
>>> [< inline >] kvm_vgic_dist_destroy
>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:271
>>> [<ffff2000080ea4bc>] kvm_vgic_destroy+0x34/0x250
>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:294
>>> but task is already holding lock:
>>> (&kvm->lock){+.+.+.}, at:
>>> [<ffff2000080ea7e4>] kvm_vgic_map_resources+0x2c/0x108
>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:343
>>> other info that might help us debug this:
>>> Possible unsafe locking scenario:
>>> CPU0
>>> ----
>>> lock(&kvm->lock);
>>> lock(&kvm->lock);
>>> *** DEADLOCK ***
>>> May be due to missing lock nesting notation
>>> 2 locks held by syz-executor/20805:
>>> #0:(&vcpu->mutex){+.+.+.}, at:
>>> [<ffff2000080bcc30>] vcpu_load+0x28/0x1d0
>>> arch/arm64/kvm/../../../virt/kvm/kvm_main.c:143
>>> #1:(&kvm->lock){+.+.+.}, at:
>>> [<ffff2000080ea7e4>] kvm_vgic_map_resources+0x2c/0x108
>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:343
>>> stack backtrace:
>>> CPU: 2 PID: 20805 Comm: syz-executor Not tainted
>>> 4.9.0-rc6-xc2-00056-g08372dd4b91d-dirty #50
>>> Hardware name: Hardkernel ODROID-C2 (DT)
>>> Call trace:
>>> [<ffff200008090560>] dump_backtrace+0x0/0x3c8 arch/arm64/kernel/traps.c:69
>>> [<ffff200008090948>] show_stack+0x20/0x30 arch/arm64/kernel/traps.c:219
>>> [< inline >] __dump_stack lib/dump_stack.c:15
>>> [<ffff200008895840>] dump_stack+0x100/0x150 lib/dump_stack.c:51
>>> [< inline >] print_deadlock_bug kernel/locking/lockdep.c:1728
>>> [< inline >] check_deadlock kernel/locking/lockdep.c:1772
>>> [< inline >] validate_chain kernel/locking/lockdep.c:2250
>>> [<ffff2000081c8718>] __lock_acquire+0x1938/0x3440 kernel/locking/lockdep.c:3335
>>> [<ffff2000081caa84>] lock_acquire+0xdc/0x1d8 kernel/locking/lockdep.c:3746
>>> [< inline >] __mutex_lock_common kernel/locking/mutex.c:521
>>> [<ffff200009700004>] mutex_lock_nested+0xdc/0x7b8 kernel/locking/mutex.c:621
>>> [< inline >] kvm_vgic_dist_destroy
>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:271
>>> [<ffff2000080ea4bc>] kvm_vgic_destroy+0x34/0x250
>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:294
>>> [<ffff2000080ec290>] vgic_v2_map_resources+0x218/0x430
>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-v2.c:295
>>> [<ffff2000080ea884>] kvm_vgic_map_resources+0xcc/0x108
>>> arch/arm64/kvm/../../../virt/kvm/arm/vgic/vgic-init.c:348
>>> [< inline >] kvm_vcpu_first_run_init
>>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:505
>>> [<ffff2000080d2768>] kvm_arch_vcpu_ioctl_run+0xab8/0xce0
>>> arch/arm64/kvm/../../../arch/arm/kvm/arm.c:591
>>> [<ffff2000080c1fec>] kvm_vcpu_ioctl+0x434/0xc08
>>> arch/arm64/kvm/../../../virt/kvm/kvm_main.c:2557
>>> [< inline >] vfs_ioctl fs/ioctl.c:43
>>> [<ffff200008450c38>] do_vfs_ioctl+0x128/0xfc0 fs/ioctl.c:679
>>> [< inline >] SYSC_ioctl fs/ioctl.c:694
>>> [<ffff200008451b78>] SyS_ioctl+0xa8/0xb8 fs/ioctl.c:685
>>> [<ffff200008083ef0>] el0_svc_naked+0x24/0x28 arch/arm64/kernel/entry.S:755
>>
>> Nice catch, and many thanks for reporting this.
>>
>> The bug is fairly obvious. Christoffer, what do you think? I don't think
>> we need to hold the kvm->lock all the way, but I'd like another pair of
>> eyes (the coffee machine is out of order again, and tea doesn't cut it).
>>
>> Thanks,
>>
>> M.
>>
>> From 93f80b20fb9351a49ee8b74eed3fc59c84651371 Mon Sep 17 00:00:00 2001
>> From: Marc Zyngier <marc.zyngier@arm.com>
>> Date: Thu, 12 Jan 2017 09:21:56 +0000
>> Subject: [PATCH] KVM: arm/arm64: vgic: Fix deadlock on error handling
>>
>> Dmitry Vyukov reported that the syzkaller fuzzer triggered a
>> deadlock in the vgic setup code when an error was detected, as
>> the cleanup code tries to take a lock that is already held by
>> the setup code.
>>
>> The fix is pretty obvious: move the cleaup call after having
>> dropped the lock, since not much can happen at that point.
> ^^^^^^^^
> Is that really true? If for instance the calls to
> vgic_register_dist_iodev() or kvm_phys_addr_ioremap() in
> vgic_v2_map_resources() fail, we leave the function with a half
> initialized VGIC (because vgic_init() succeeded).
But we only set dist->ready to true when everything went OK. How is
that an issue?
> Dropping the lock at
> this point without having the GIC cleaned up before sounds a bit
> suspicious (I may be wrong on this, though).
Thinking of it, that may open a race with vgic init call, leading to
leaking distributor memory.
>
> Can't we just document that kvm_vgic_destroy() needs to be called with
> the kvm->lock held and take the lock around the only other caller
> (kvm_arch_destroy_vm() in arch/arm/kvm/arm.c)?
> We can then keep holding the lock in the map_resources calls.
> Though we might still move the calls to kvm_vgic_destroy() into the
> wrapper function as a cleanup (as shown below), just before dropping the
> lock.
I'd rather keep the changes limited to the vgic code, and save myself
having to document more locking (we already have our fair share here).
How about this (untested):
>From 24dc3f5750da20d89e0ce9b7855d125d0100bee8 Mon Sep 17 00:00:00 2001
From: Marc Zyngier <marc.zyngier@arm.com>
Date: Thu, 12 Jan 2017 09:21:56 +0000
Subject: [PATCH] KVM: arm/arm64: vgic: Fix deadlock on error handling
Dmitry Vyukov reported that the syzkaller fuzzer triggered a
deadlock in the vgic setup code when an error was detected, as
the cleanup code tries to take a lock that is already held by
the setup code.
The fix is to avoid retaking the lock when cleaning up, by
telling the cleanup function that we already hold it.
Cc: stable at vger.kernel.org
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/vgic/vgic-init.c | 21 ++++++++++++++++-----
virt/kvm/arm/vgic/vgic-v2.c | 2 --
virt/kvm/arm/vgic/vgic-v3.c | 2 --
3 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 5114391..30d74e2 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -264,11 +264,12 @@ int vgic_init(struct kvm *kvm)
return ret;
}
-static void kvm_vgic_dist_destroy(struct kvm *kvm)
+static void kvm_vgic_dist_destroy(struct kvm *kvm, bool locked)
{
struct vgic_dist *dist = &kvm->arch.vgic;
- mutex_lock(&kvm->lock);
+ if (!locked)
+ mutex_lock(&kvm->lock);
dist->ready = false;
dist->initialized = false;
@@ -276,7 +277,8 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
kfree(dist->spis);
dist->nr_spis = 0;
- mutex_unlock(&kvm->lock);
+ if (!locked)
+ mutex_unlock(&kvm->lock);
}
void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
@@ -286,17 +288,22 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
}
-void kvm_vgic_destroy(struct kvm *kvm)
+static void kvm_vgic_destroy_locked(struct kvm *kvm, bool locked)
{
struct kvm_vcpu *vcpu;
int i;
- kvm_vgic_dist_destroy(kvm);
+ kvm_vgic_dist_destroy(kvm, locked);
kvm_for_each_vcpu(i, vcpu, kvm)
kvm_vgic_vcpu_destroy(vcpu);
}
+void kvm_vgic_destroy(struct kvm *kvm)
+{
+ kvm_vgic_destroy_locked(kvm, false);
+}
+
/**
* vgic_lazy_init: Lazy init is only allowed if the GIC exposed to the guest
* is a GICv2. A GICv3 must be explicitly initialized by the guest using the
@@ -348,6 +355,10 @@ int kvm_vgic_map_resources(struct kvm *kvm)
ret = vgic_v2_map_resources(kvm);
else
ret = vgic_v3_map_resources(kvm);
+
+ if (ret)
+ kvm_vgic_destroy_locked(kvm, true);
+
out:
mutex_unlock(&kvm->lock);
return ret;
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 9bab867..834137e 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -293,8 +293,6 @@ int vgic_v2_map_resources(struct kvm *kvm)
dist->ready = true;
out:
- if (ret)
- kvm_vgic_destroy(kvm);
return ret;
}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 7df1b90..a4c7fff 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -308,8 +308,6 @@ int vgic_v3_map_resources(struct kvm *kvm)
dist->ready = true;
out:
- if (ret)
- kvm_vgic_destroy(kvm);
return ret;
}
--
2.1.4
--
Jazz is not dead. It just smells funny...
^ 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