* [PATCH RESEND v11 6/8] namei: aggressively check for nd->root escape on ".." resolution
From: Aleksa Sarai @ 2019-08-20 3:34 UTC (permalink / raw)
To: Al Viro, Jeff Layton, J. Bruce Fields, Arnd Bergmann,
David Howells, Shuah Khan, Shuah Khan
Cc: linux-ia64, linux-sh, Alexei Starovoitov, Oleg Nesterov,
linux-kselftest, sparclinux, linux-arch, linux-s390,
Tycho Andersen, Aleksa Sarai, linux-arm-kernel, linux-mips,
linux-xtensa, Kees Cook, Jann Horn, linuxppc-dev, Aleksa Sarai,
Andy Lutomirski, David Drysdale, Christian Brauner, linux-parisc,
linux-m68k, linux-api, Chanho Min, linux-kernel, Eric Biederman,
linux-alpha, linux-fsdevel, Andrew Morton, Linus Torvalds,
containers
In-Reply-To: <20190820033406.29796-1-cyphar@cyphar.com>
This patch allows for LOOKUP_BENEATH and LOOKUP_IN_ROOT to safely permit
".." resolution (in the case of LOOKUP_BENEATH the resolution will still
fail if ".." resolution would resolve a path outside of the root --
while LOOKUP_IN_ROOT will chroot(2)-style scope it). Magic-link jumps
are still disallowed entirely because now they could result in
inconsistent behaviour if resolution encounters a subsequent ".."[*].
The need for this patch is explained by observing there is a fairly
easy-to-exploit race condition with chroot(2) (and thus by extension
LOOKUP_IN_ROOT and LOOKUP_BENEATH if ".." is allowed) where a rename(2)
of a path can be used to "skip over" nd->root and thus escape to the
filesystem above nd->root.
thread1 [attacker]:
for (;;)
renameat2(AT_FDCWD, "/a/b/c", AT_FDCWD, "/a/d", RENAME_EXCHANGE);
thread2 [victim]:
for (;;)
openat2(dirb, "b/c/../../etc/shadow",
{ .flags = O_PATH, .resolve = RESOLVE_IN_ROOT } );
With fairly significant regularity, thread2 will resolve to
"/etc/shadow" rather than "/a/b/etc/shadow". There is also a similar
(though somewhat more privileged) attack using MS_MOVE.
With this patch, such cases will be detected *during* ".." resolution
(which is the weak point of chroot(2) -- since walking *into* a
subdirectory tautologically cannot result in you walking *outside*
nd->root -- except through a bind-mount or magic-link). By detecting
this at ".." resolution (rather than checking only at the end of the
entire resolution) we can both correct escapes by jumping back to the
root (in the case of LOOKUP_IN_ROOT), as well as avoid revealing to
attackers the structure of the filesystem outside of the root (through
timing attacks for instance).
In order to avoid a quadratic lookup with each ".." entry, we only
activate the slow path if a write through &rename_lock or &mount_lock
has occurred during path resolution (&rename_lock and &mount_lock are
re-taken to further optimise the lookup). Since the primary attack being
protected against is MS_MOVE or rename(2), not doing additional checks
unless a mount or rename have occurred avoids making the common case
slow.
The use of path_is_under() here might seem suspect, but on further
inspection of the most important race (a path was *inside* the root but
is now *outside*), there appears to be no attack potential:
* If path_is_under() occurs before the rename, then the path will be
resolved -- however the path was originally inside the root and thus
there is no escape (and to userspace it'd look like the rename
occurred after the path was resolved). If path_is_under() occurs
afterwards, the resolution is blocked.
* Subsequent ".." jumps are guaranteed to check path_is_under() -- by
construction, &rename_lock or &mount_lock must have been taken by
the attacker after path_is_under() returned in the victim. Thus ".."
will not be able to escape from the previously-inside-root path.
* Walking down in the moved path is still safe since the entire
subtree was moved (either by rename(2) or MS_MOVE) and because (as
discussed above) walking down is safe.
A variant of the above attack is included in the selftests for
openat2(2) later in this patch series. I've run this test on several
machines for several days and no instances of a breakout were detected.
While this is not concrete proof that this is safe, when combined with
the above argument it should lend some trustworthiness to this
construction.
[*] It may be acceptable in the future to do a path_is_under() check
after resolving a magic-link and permit resolution if the
nd_jump_link() result is still within the dirfd. However this seems
unlikely to be a feature that people *really* need* -- it can be
added later if it turns out a lot of people want it.
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Jann Horn <jannh@google.com>
Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
fs/namei.c | 45 +++++++++++++++++++++++++++++++--------------
1 file changed, 31 insertions(+), 14 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 0352d275bd13..fd1eb5ce8baa 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -491,7 +491,7 @@ struct nameidata {
struct path root;
struct inode *inode; /* path.dentry.d_inode */
unsigned int flags;
- unsigned seq, m_seq;
+ unsigned seq, m_seq, r_seq;
int last_type;
unsigned depth;
int total_link_count;
@@ -1758,22 +1758,36 @@ static inline int handle_dots(struct nameidata *nd, int type)
if (type == LAST_DOTDOT) {
int error = 0;
- /*
- * LOOKUP_BENEATH resolving ".." is not currently safe -- races
- * can cause our parent to have moved outside of the root and
- * us to skip over it.
- */
- if (unlikely(nd->flags & (LOOKUP_BENEATH | LOOKUP_IN_ROOT)))
- return -EXDEV;
if (!nd->root.mnt) {
error = set_root(nd);
if (error)
return error;
}
- if (nd->flags & LOOKUP_RCU) {
- return follow_dotdot_rcu(nd);
- } else
- return follow_dotdot(nd);
+ if (nd->flags & LOOKUP_RCU)
+ error = follow_dotdot_rcu(nd);
+ else
+ error = follow_dotdot(nd);
+ if (error)
+ return error;
+
+ if (unlikely(nd->flags & (LOOKUP_BENEATH | LOOKUP_IN_ROOT))) {
+ bool m_retry = read_seqretry(&mount_lock, nd->m_seq);
+ bool r_retry = read_seqretry(&rename_lock, nd->r_seq);
+
+ /*
+ * Don't bother checking unless there's a racing
+ * rename(2) or MS_MOVE.
+ */
+ if (likely(!m_retry && !r_retry))
+ return 0;
+
+ if (m_retry && !(nd->flags & LOOKUP_RCU))
+ nd->m_seq = read_seqbegin(&mount_lock);
+ if (r_retry)
+ nd->r_seq = read_seqbegin(&rename_lock);
+ if (!path_is_under(&nd->path, &nd->root))
+ return -EXDEV;
+ }
}
return 0;
}
@@ -2245,6 +2259,11 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
nd->depth = 0;
+
+ nd->m_seq = read_seqbegin(&mount_lock);
+ if (flags & (LOOKUP_BENEATH | LOOKUP_IN_ROOT))
+ nd->r_seq = read_seqbegin(&rename_lock);
+
if (flags & LOOKUP_ROOT) {
struct dentry *root = nd->root.dentry;
struct inode *inode = root->d_inode;
@@ -2266,8 +2285,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->path.mnt = NULL;
nd->path.dentry = NULL;
- nd->m_seq = read_seqbegin(&mount_lock);
-
/* LOOKUP_IN_ROOT treats absolute paths as being relative-to-dirfd. */
if (flags & LOOKUP_IN_ROOT)
while (*s == '/')
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH RESEND v11 5/8] namei: LOOKUP_IN_ROOT: chroot-like path resolution
From: Aleksa Sarai @ 2019-08-20 3:34 UTC (permalink / raw)
To: Al Viro, Jeff Layton, J. Bruce Fields, Arnd Bergmann,
David Howells, Shuah Khan, Shuah Khan
Cc: linux-ia64, linux-sh, Alexei Starovoitov, Oleg Nesterov,
linux-kselftest, sparclinux, linux-arch, linux-s390,
Tycho Andersen, Aleksa Sarai, linux-arm-kernel, linux-mips,
linux-xtensa, Kees Cook, Jann Horn, linuxppc-dev, Aleksa Sarai,
Andy Lutomirski, David Drysdale, Christian Brauner, linux-parisc,
linux-m68k, linux-api, Chanho Min, linux-kernel, Eric Biederman,
linux-alpha, linux-fsdevel, Andrew Morton, Linus Torvalds,
containers
In-Reply-To: <20190820033406.29796-1-cyphar@cyphar.com>
The primary motivation for the need for this flag is container runtimes
which have to interact with malicious root filesystems in the host
namespaces. One of the first requirements for a container runtime to be
secure against a malicious rootfs is that they correctly scope symlinks
(that is, they should be scoped as though they are chroot(2)ed into the
container's rootfs) and ".."-style paths[*]. The already-existing
LOOKUP_NO_XDEV and LOOKUP_NO_MAGICLINKS help defend against other
potential attacks in a malicious rootfs scenario.
Currently most container runtimes try to do this resolution in
userspace[1], causing many potential race conditions. In addition, the
"obvious" alternative (actually performing a {ch,pivot_}root(2))
requires a fork+exec (for some runtimes) which is *very* costly if
necessary for every filesystem operation involving a container.
[*] At the moment, ".." and magic-link jumping are disallowed for the
same reason it is disabled for LOOKUP_BENEATH -- currently it is not
safe to allow it. Future patches may enable it unconditionally once
we have resolved the possible races (for "..") and semantics (for
magic-link jumping).
The most significant *at(2) semantic change with LOOKUP_IN_ROOT is that
absolute pathnames no longer cause the dirfd to be ignored completely.
The rationale is that LOOKUP_IN_ROOT must necessarily chroot-scope
symlinks with absolute paths to dirfd, and so doing it for the base path
seems to be the most consistent behaviour (and also avoids foot-gunning
users who want to scope paths that are absolute).
[1]: https://github.com/cyphar/filepath-securejoin
Suggested-by: Christian Brauner <christian@brauner.io>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
fs/namei.c | 41 +++++++++++++++++++++++++++++++----------
include/linux/namei.h | 1 +
2 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 2e18ce5a313e..0352d275bd13 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -676,7 +676,7 @@ static int unlazy_walk(struct nameidata *nd)
goto out1;
if (!nd->root.mnt) {
/* Restart from path_init() if nd->root was cleared. */
- if (nd->flags & LOOKUP_BENEATH)
+ if (nd->flags & (LOOKUP_BENEATH | LOOKUP_IN_ROOT))
goto out;
} else if (!(nd->flags & LOOKUP_ROOT)) {
if (unlikely(!legitimize_path(nd, &nd->root, nd->root_seq)))
@@ -809,10 +809,18 @@ static int complete_walk(struct nameidata *nd)
return status;
}
-static void set_root(struct nameidata *nd)
+static int set_root(struct nameidata *nd)
{
struct fs_struct *fs = current->fs;
+ /*
+ * Jumping to the real root as part of LOOKUP_IN_ROOT is a BUG in namei,
+ * but we still have to ensure it doesn't happen because it will cause a
+ * breakout from the dirfd.
+ */
+ if (WARN_ON(nd->flags & LOOKUP_IN_ROOT))
+ return -ENOTRECOVERABLE;
+
if (nd->flags & LOOKUP_RCU) {
unsigned seq;
@@ -824,6 +832,7 @@ static void set_root(struct nameidata *nd)
} else {
get_fs_root(fs, &nd->root);
}
+ return 0;
}
static void path_put_conditional(struct path *path, struct nameidata *nd)
@@ -854,6 +863,11 @@ static int nd_jump_root(struct nameidata *nd)
if (nd->path.mnt != NULL && nd->path.mnt != nd->root.mnt)
return -EXDEV;
}
+ if (!nd->root.mnt) {
+ int error = set_root(nd);
+ if (error)
+ return error;
+ }
if (nd->flags & LOOKUP_RCU) {
struct dentry *d;
nd->path = nd->root;
@@ -1100,15 +1114,13 @@ const char *get_link(struct nameidata *nd)
if (unlikely(nd->flags & LOOKUP_NO_MAGICLINKS))
return ERR_PTR(-ELOOP);
/* Not currently safe. */
- if (unlikely(nd->flags & LOOKUP_BENEATH))
+ if (unlikely(nd->flags & (LOOKUP_BENEATH | LOOKUP_IN_ROOT)))
return ERR_PTR(-EXDEV);
}
if (IS_ERR_OR_NULL(res))
return res;
}
if (*res == '/') {
- if (!nd->root.mnt)
- set_root(nd);
error = nd_jump_root(nd);
if (unlikely(error))
return ERR_PTR(error);
@@ -1744,15 +1756,20 @@ static inline int may_lookup(struct nameidata *nd)
static inline int handle_dots(struct nameidata *nd, int type)
{
if (type == LAST_DOTDOT) {
+ int error = 0;
+
/*
* LOOKUP_BENEATH resolving ".." is not currently safe -- races
* can cause our parent to have moved outside of the root and
* us to skip over it.
*/
- if (unlikely(nd->flags & LOOKUP_BENEATH))
+ if (unlikely(nd->flags & (LOOKUP_BENEATH | LOOKUP_IN_ROOT)))
return -EXDEV;
- if (!nd->root.mnt)
- set_root(nd);
+ if (!nd->root.mnt) {
+ error = set_root(nd);
+ if (error)
+ return error;
+ }
if (nd->flags & LOOKUP_RCU) {
return follow_dotdot_rcu(nd);
} else
@@ -2251,9 +2268,13 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->m_seq = read_seqbegin(&mount_lock);
+ /* LOOKUP_IN_ROOT treats absolute paths as being relative-to-dirfd. */
+ if (flags & LOOKUP_IN_ROOT)
+ while (*s == '/')
+ s++;
+
/* Figure out the starting path and root (if needed). */
if (*s == '/') {
- set_root(nd);
error = nd_jump_root(nd);
if (unlikely(error))
return ERR_PTR(error);
@@ -2298,7 +2319,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
fdput(f);
}
/* For scoped-lookups we need to set the root to the dirfd as well. */
- if (flags & LOOKUP_BENEATH) {
+ if (flags & (LOOKUP_BENEATH | LOOKUP_IN_ROOT)) {
nd->root = nd->path;
if (flags & LOOKUP_RCU)
nd->root_seq = nd->seq;
diff --git a/include/linux/namei.h b/include/linux/namei.h
index be407415c28a..ec2c6c588ea7 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -57,6 +57,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_NO_MAGICLINKS 0x080000 /* No /proc/$pid/fd/ "symlink" crossing. */
#define LOOKUP_NO_SYMLINKS 0x100000 /* No symlink crossing *at all*.
Implies LOOKUP_NO_MAGICLINKS. */
+#define LOOKUP_IN_ROOT 0x200000 /* Treat dirfd as %current->fs->root. */
extern int path_pts(struct path *path);
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH RESEND v11 4/8] namei: O_BENEATH-style path resolution flags
From: Aleksa Sarai @ 2019-08-20 3:34 UTC (permalink / raw)
To: Al Viro, Jeff Layton, J. Bruce Fields, Arnd Bergmann,
David Howells, Shuah Khan, Shuah Khan
Cc: linux-ia64, linux-sh, Alexei Starovoitov, Oleg Nesterov,
linux-kselftest, sparclinux, linux-arch, linux-s390,
Tycho Andersen, Aleksa Sarai, linux-arm-kernel, linux-mips,
linux-xtensa, Kees Cook, Jann Horn, linuxppc-dev, Aleksa Sarai,
Andy Lutomirski, David Drysdale, Christian Brauner, linux-parisc,
linux-m68k, linux-api, Chanho Min, linux-kernel, Eric Biederman,
linux-alpha, linux-fsdevel, Andrew Morton, Linus Torvalds,
containers
In-Reply-To: <20190820033406.29796-1-cyphar@cyphar.com>
Add the following flags to allow various restrictions on path resolution
(these affect the *entire* resolution, rather than just the final path
component -- as is the case with LOOKUP_FOLLOW).
The primary justification for these flags is to allow for programs to be
far more strict about how they want path resolution to handle symlinks,
mountpoint crossings, and paths that escape the dirfd (through an
absolute path or ".." shenanigans).
This is of particular concern to container runtimes that want to be very
careful about malicious root filesystems that a container's init might
have screwed around with (and there is no real way to protect against
this in userspace if you consider potential races against a malicious
container's init). More classical applications (which have their own
potentially buggy userspace path sanitisation code) include web servers,
archive extraction tools, network file servers, and so on.
These flags are exposed to userspace through openat2(2) in a later
patchset.
* LOOKUP_NO_XDEV: Disallow mount-point crossing (both *down* into one,
or *up* from one). Both bind-mounts and cross-filesystem mounts are
blocked by this flag. The naming is based on "find -xdev" as well as
-EXDEV (though find(1) doesn't walk upwards, the semantics seem
obvious).
* LOOKUP_NO_MAGICLINKS: Disallows ->get_link "symlink" (or rather,
magic-link) jumping. This is a very specific restriction, and it
exists because /proc/$pid/fd/... "symlinks" allow for access outside
nd->root and pose risk to container runtimes that don't want to be
tricked into accessing a host path (but do want to allow
no-funny-business symlink resolution).
* LOOKUP_NO_SYMLINKS: Disallows resolution through symlinks of any kind
(including magic-links).
* LOOKUP_BENEATH: Disallow "escapes" from the starting point of the
filesystem tree during resolution (you must stay "beneath" the
starting point at all times). Currently this is done by disallowing
".." and absolute paths (either in the given path or found during
symlink resolution) entirely, as well as all magic-link jumping.
The wholesale banning of ".." is because it is currently not safe to
allow ".." resolution (races can cause the path to be moved outside of
the root -- this is conceptually similar to historical chroot(2)
escape attacks). Future patches in this series will address this, and
will re-enable ".." resolution once it is safe. With those patches,
".." resolution will only be allowed if it remains in the root
throughout resolution (such as "a/../b" not "a/../../outside/b").
The banning of magic-link jumping is done because it is not clear
whether semantically they should be allowed -- while some magic-links
are safe there are many that can cause escapes (and once a
resolution is outside of the root, O_BENEATH will no longer detect
it). Future patches may re-enable magic-link jumping when such jumps
would remain inside the root.
The LOOKUP_NO_*LINK flags return -ELOOP if path resolution would
violates their requirement, while the others all return -EXDEV.
This is a refresh of Al's AT_NO_JUMPS patchset[1] (which was a variation
on David Drysdale's O_BENEATH patchset[2], which in turn was based on
the Capsicum project[3]). Input from Linus and Andy in the AT_NO_JUMPS
thread[4] determined most of the API changes made in this refresh.
[1]: https://lwn.net/Articles/721443/
[2]: https://lwn.net/Articles/619151/
[3]: https://lwn.net/Articles/603929/
[4]: https://lwn.net/Articles/723057/
Cc: Christian Brauner <christian@brauner.io>
Suggested-by: David Drysdale <drysdale@google.com>
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Suggested-by: Andy Lutomirski <luto@kernel.org>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
fs/namei.c | 85 ++++++++++++++++++++++++++++++++++++-------
include/linux/namei.h | 7 ++++
2 files changed, 78 insertions(+), 14 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index e39b573fcc4d..2e18ce5a313e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -674,7 +674,11 @@ static int unlazy_walk(struct nameidata *nd)
goto out2;
if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
goto out1;
- if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
+ if (!nd->root.mnt) {
+ /* Restart from path_init() if nd->root was cleared. */
+ if (nd->flags & LOOKUP_BENEATH)
+ goto out;
+ } else if (!(nd->flags & LOOKUP_ROOT)) {
if (unlikely(!legitimize_path(nd, &nd->root, nd->root_seq)))
goto out;
}
@@ -843,6 +847,13 @@ static inline void path_to_nameidata(const struct path *path,
static int nd_jump_root(struct nameidata *nd)
{
+ if (unlikely(nd->flags & LOOKUP_BENEATH))
+ return -EXDEV;
+ if (unlikely(nd->flags & LOOKUP_NO_XDEV)) {
+ /* Absolute path arguments to path_init() are allowed. */
+ if (nd->path.mnt != NULL && nd->path.mnt != nd->root.mnt)
+ return -EXDEV;
+ }
if (nd->flags & LOOKUP_RCU) {
struct dentry *d;
nd->path = nd->root;
@@ -1051,6 +1062,9 @@ const char *get_link(struct nameidata *nd)
int error;
const char *res;
+ if (unlikely(nd->flags & LOOKUP_NO_SYMLINKS))
+ return ERR_PTR(-ELOOP);
+
if (!(nd->flags & LOOKUP_RCU)) {
touch_atime(&last->link);
cond_resched();
@@ -1082,14 +1096,22 @@ const char *get_link(struct nameidata *nd)
} else {
res = get(dentry, inode, &last->done);
}
+ if (nd->flags & LOOKUP_MAGICLINK_JUMPED) {
+ if (unlikely(nd->flags & LOOKUP_NO_MAGICLINKS))
+ return ERR_PTR(-ELOOP);
+ /* Not currently safe. */
+ if (unlikely(nd->flags & LOOKUP_BENEATH))
+ return ERR_PTR(-EXDEV);
+ }
if (IS_ERR_OR_NULL(res))
return res;
}
if (*res == '/') {
if (!nd->root.mnt)
set_root(nd);
- if (unlikely(nd_jump_root(nd)))
- return ERR_PTR(-ECHILD);
+ error = nd_jump_root(nd);
+ if (unlikely(error))
+ return ERR_PTR(error);
while (unlikely(*++res == '/'))
;
}
@@ -1270,12 +1292,16 @@ static int follow_managed(struct path *path, struct nameidata *nd)
break;
}
- if (need_mntput && path->mnt == mnt)
- mntput(path->mnt);
+ if (need_mntput) {
+ if (path->mnt == mnt)
+ mntput(path->mnt);
+ if (unlikely(nd->flags & LOOKUP_NO_XDEV))
+ ret = -EXDEV;
+ else
+ nd->flags |= LOOKUP_JUMPED;
+ }
if (ret == -EISDIR || !ret)
ret = 1;
- if (need_mntput)
- nd->flags |= LOOKUP_JUMPED;
if (unlikely(ret < 0))
path_put_conditional(path, nd);
return ret;
@@ -1332,6 +1358,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
mounted = __lookup_mnt(path->mnt, path->dentry);
if (!mounted)
break;
+ if (unlikely(nd->flags & LOOKUP_NO_XDEV))
+ return false;
path->mnt = &mounted->mnt;
path->dentry = mounted->mnt.mnt_root;
nd->flags |= LOOKUP_JUMPED;
@@ -1352,8 +1380,11 @@ static int follow_dotdot_rcu(struct nameidata *nd)
struct inode *inode = nd->inode;
while (1) {
- if (path_equal(&nd->path, &nd->root))
+ if (path_equal(&nd->path, &nd->root)) {
+ if (unlikely(nd->flags & LOOKUP_BENEATH))
+ return -EXDEV;
break;
+ }
if (nd->path.dentry != nd->path.mnt->mnt_root) {
struct dentry *old = nd->path.dentry;
struct dentry *parent = old->d_parent;
@@ -1378,6 +1409,8 @@ static int follow_dotdot_rcu(struct nameidata *nd)
return -ECHILD;
if (&mparent->mnt == nd->path.mnt)
break;
+ if (unlikely(nd->flags & LOOKUP_NO_XDEV))
+ return -EXDEV;
/* we know that mountpoint was pinned */
nd->path.dentry = mountpoint;
nd->path.mnt = &mparent->mnt;
@@ -1392,6 +1425,8 @@ static int follow_dotdot_rcu(struct nameidata *nd)
return -ECHILD;
if (!mounted)
break;
+ if (unlikely(nd->flags & LOOKUP_NO_XDEV))
+ return -EXDEV;
nd->path.mnt = &mounted->mnt;
nd->path.dentry = mounted->mnt.mnt_root;
inode = nd->path.dentry->d_inode;
@@ -1480,8 +1515,11 @@ static int path_parent_directory(struct path *path)
static int follow_dotdot(struct nameidata *nd)
{
while(1) {
- if (path_equal(&nd->path, &nd->root))
+ if (path_equal(&nd->path, &nd->root)) {
+ if (unlikely(nd->flags & LOOKUP_BENEATH))
+ return -EXDEV;
break;
+ }
if (nd->path.dentry != nd->path.mnt->mnt_root) {
int ret = path_parent_directory(&nd->path);
if (ret)
@@ -1490,6 +1528,8 @@ static int follow_dotdot(struct nameidata *nd)
}
if (!follow_up(&nd->path))
break;
+ if (unlikely(nd->flags & LOOKUP_NO_XDEV))
+ return -EXDEV;
}
follow_mount(&nd->path);
nd->inode = nd->path.dentry->d_inode;
@@ -1704,6 +1744,13 @@ static inline int may_lookup(struct nameidata *nd)
static inline int handle_dots(struct nameidata *nd, int type)
{
if (type == LAST_DOTDOT) {
+ /*
+ * LOOKUP_BENEATH resolving ".." is not currently safe -- races
+ * can cause our parent to have moved outside of the root and
+ * us to skip over it.
+ */
+ if (unlikely(nd->flags & LOOKUP_BENEATH))
+ return -EXDEV;
if (!nd->root.mnt)
set_root(nd);
if (nd->flags & LOOKUP_RCU) {
@@ -2170,6 +2217,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
/* must be paired with terminate_walk() */
static const char *path_init(struct nameidata *nd, unsigned flags)
{
+ int error;
const char *s = nd->name->name;
if (!*s)
@@ -2202,11 +2250,13 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->path.dentry = NULL;
nd->m_seq = read_seqbegin(&mount_lock);
+
+ /* Figure out the starting path and root (if needed). */
if (*s == '/') {
set_root(nd);
- if (likely(!nd_jump_root(nd)))
- return s;
- return ERR_PTR(-ECHILD);
+ error = nd_jump_root(nd);
+ if (unlikely(error))
+ return ERR_PTR(error);
} else if (nd->dfd == AT_FDCWD) {
if (flags & LOOKUP_RCU) {
struct fs_struct *fs = current->fs;
@@ -2222,7 +2272,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
get_fs_pwd(current->fs, &nd->path);
nd->inode = nd->path.dentry->d_inode;
}
- return s;
} else {
/* Caller must check execute permissions on the starting path component */
struct fd f = fdget_raw(nd->dfd);
@@ -2247,8 +2296,16 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->inode = nd->path.dentry->d_inode;
}
fdput(f);
- return s;
}
+ /* For scoped-lookups we need to set the root to the dirfd as well. */
+ if (flags & LOOKUP_BENEATH) {
+ nd->root = nd->path;
+ if (flags & LOOKUP_RCU)
+ nd->root_seq = nd->seq;
+ else
+ path_get(&nd->root);
+ }
+ return s;
}
static const char *trailing_symlink(struct nameidata *nd)
diff --git a/include/linux/namei.h b/include/linux/namei.h
index bd6d3eb7764d..be407415c28a 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -51,6 +51,13 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_DOWN 0x8000
#define LOOKUP_MAGICLINK_JUMPED 0x10000
+/* Scoping flags for lookup. */
+#define LOOKUP_BENEATH 0x020000 /* No escaping from starting point. */
+#define LOOKUP_NO_XDEV 0x040000 /* No mountpoint crossing. */
+#define LOOKUP_NO_MAGICLINKS 0x080000 /* No /proc/$pid/fd/ "symlink" crossing. */
+#define LOOKUP_NO_SYMLINKS 0x100000 /* No symlink crossing *at all*.
+ Implies LOOKUP_NO_MAGICLINKS. */
+
extern int path_pts(struct path *path);
extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH RESEND v11 3/8] open: O_EMPTYPATH: procfs-less file descriptor re-opening
From: Aleksa Sarai @ 2019-08-20 3:34 UTC (permalink / raw)
To: Al Viro, Jeff Layton, J. Bruce Fields, Arnd Bergmann,
David Howells, Shuah Khan, Shuah Khan
Cc: linux-ia64, linux-sh, Alexei Starovoitov, Oleg Nesterov,
linux-kselftest, sparclinux, linux-arch, linux-s390,
Tycho Andersen, Aleksa Sarai, linux-arm-kernel, linux-mips,
linux-xtensa, Kees Cook, Jann Horn, linuxppc-dev, Aleksa Sarai,
Andy Lutomirski, David Drysdale, Christian Brauner, linux-parisc,
linux-m68k, linux-api, Chanho Min, linux-kernel, Eric Biederman,
linux-alpha, linux-fsdevel, Andrew Morton, Linus Torvalds,
containers
In-Reply-To: <20190820033406.29796-1-cyphar@cyphar.com>
Userspace has made use of /proc/self/fd very liberally to allow for
descriptors to be re-opened. There are a wide variety of uses for this
feature, but it has always required constructing a pathname and could
not be done without procfs mounted. The obvious solution for this is to
extend openat(2) to have an AT_EMPTY_PATH-equivalent -- O_EMPTYPATH.
Now that descriptor re-opening has been made safe through the new
magic-link resolution restrictions, we can replicate these restrictions
for O_EMPTYPATH. In particular, we only allow "upgrading" the file
descriptor if the corresponding FMODE_PATH_* bit is set (or the
FMODE_{READ,WRITE} cases for non-O_PATH file descriptors).
When doing openat(O_EMPTYPATH|O_PATH), O_PATH takes precedence and
O_EMPTYPATH is ignored. Very few users ever have a need to O_PATH
re-open an existing file descriptor, and so accommodating them at the
expense of further complicating O_PATH makes little sense. Ultimately,
if users ask for this we can always add RESOLVE_EMPTY_PATH to
resolveat(2) in the future.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
arch/alpha/include/uapi/asm/fcntl.h | 1 +
arch/parisc/include/uapi/asm/fcntl.h | 39 ++++++++++++++--------------
arch/sparc/include/uapi/asm/fcntl.h | 1 +
fs/fcntl.c | 2 +-
fs/namei.c | 20 ++++++++++++++
fs/open.c | 7 ++++-
include/linux/fcntl.h | 2 +-
include/uapi/asm-generic/fcntl.h | 4 +++
8 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h
index 50bdc8e8a271..1f879bade68b 100644
--- a/arch/alpha/include/uapi/asm/fcntl.h
+++ b/arch/alpha/include/uapi/asm/fcntl.h
@@ -34,6 +34,7 @@
#define O_PATH 040000000
#define __O_TMPFILE 0100000000
+#define O_EMPTYPATH 0200000000
#define F_GETLK 7
#define F_SETLK 8
diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h
index 03ce20e5ad7d..5d709058a76f 100644
--- a/arch/parisc/include/uapi/asm/fcntl.h
+++ b/arch/parisc/include/uapi/asm/fcntl.h
@@ -2,26 +2,27 @@
#ifndef _PARISC_FCNTL_H
#define _PARISC_FCNTL_H
-#define O_APPEND 000000010
-#define O_BLKSEEK 000000100 /* HPUX only */
-#define O_CREAT 000000400 /* not fcntl */
-#define O_EXCL 000002000 /* not fcntl */
-#define O_LARGEFILE 000004000
-#define __O_SYNC 000100000
+#define O_APPEND 0000000010
+#define O_BLKSEEK 0000000100 /* HPUX only */
+#define O_CREAT 0000000400 /* not fcntl */
+#define O_EXCL 0000002000 /* not fcntl */
+#define O_LARGEFILE 0000004000
+#define __O_SYNC 0000100000
#define O_SYNC (__O_SYNC|O_DSYNC)
-#define O_NONBLOCK 000200004 /* HPUX has separate NDELAY & NONBLOCK */
-#define O_NOCTTY 000400000 /* not fcntl */
-#define O_DSYNC 001000000 /* HPUX only */
-#define O_RSYNC 002000000 /* HPUX only */
-#define O_NOATIME 004000000
-#define O_CLOEXEC 010000000 /* set close_on_exec */
-
-#define O_DIRECTORY 000010000 /* must be a directory */
-#define O_NOFOLLOW 000000200 /* don't follow links */
-#define O_INVISIBLE 004000000 /* invisible I/O, for DMAPI/XDSM */
-
-#define O_PATH 020000000
-#define __O_TMPFILE 040000000
+#define O_NONBLOCK 0000200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define O_NOCTTY 0000400000 /* not fcntl */
+#define O_DSYNC 0001000000 /* HPUX only */
+#define O_RSYNC 0002000000 /* HPUX only */
+#define O_NOATIME 0004000000
+#define O_CLOEXEC 0010000000 /* set close_on_exec */
+
+#define O_DIRECTORY 0000010000 /* must be a directory */
+#define O_NOFOLLOW 0000000200 /* don't follow links */
+#define O_INVISIBLE 0004000000 /* invisible I/O, for DMAPI/XDSM */
+
+#define O_PATH 0020000000
+#define __O_TMPFILE 0040000000
+#define O_EMPTYPATH 0100000000
#define F_GETLK64 8
#define F_SETLK64 9
diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h
index 67dae75e5274..dc86c9eaf950 100644
--- a/arch/sparc/include/uapi/asm/fcntl.h
+++ b/arch/sparc/include/uapi/asm/fcntl.h
@@ -37,6 +37,7 @@
#define O_PATH 0x1000000
#define __O_TMPFILE 0x2000000
+#define O_EMPTYPATH 0x4000000
#define F_GETOWN 5 /* for sockets. */
#define F_SETOWN 6 /* for sockets. */
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 3d40771e8e7c..4cf05a2fd162 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -1031,7 +1031,7 @@ static int __init fcntl_init(void)
* Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
* is defined as O_NONBLOCK on some platforms and not on others.
*/
- BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ !=
+ BUILD_BUG_ON(22 - 1 /* for O_RDONLY being 0 */ !=
HWEIGHT32(
(VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) |
__FMODE_EXEC | __FMODE_NONOTIFY));
diff --git a/fs/namei.c b/fs/namei.c
index 54d57dad0f91..e39b573fcc4d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3571,6 +3571,24 @@ static int trailing_magiclink(struct nameidata *nd, int acc_mode,
return may_open_magiclink(upgrade_mask, acc_mode);
}
+static int do_emptypath(struct nameidata *nd, const struct open_flags *op,
+ struct file *file)
+{
+ int error;
+ /* We don't support AT_FDCWD (since O_PATH is disallowed here). */
+ struct fd f = fdget_raw(nd->dfd);
+
+ if (!f.file)
+ return -EBADF;
+
+ /* Apply trailing_magiclink()-like restrictions. */
+ error = may_open_magiclink(f.file->f_mode, op->acc_mode);
+ if (!error)
+ error = vfs_open(&f.file->f_path, file);
+ fdput(f);
+ return error;
+}
+
static struct file *path_openat(struct nameidata *nd,
const struct open_flags *op, unsigned flags)
{
@@ -3583,6 +3601,8 @@ static struct file *path_openat(struct nameidata *nd,
if (unlikely(file->f_flags & __O_TMPFILE)) {
error = do_tmpfile(nd, flags, op, file);
+ } else if (unlikely(file->f_flags & O_EMPTYPATH)) {
+ error = do_emptypath(nd, op, file);
} else if (unlikely(file->f_flags & O_PATH)) {
/* Inlined path_lookupat() with a trailing_magiclink() check. */
fmode_t opath_mask = op->opath_mask;
diff --git a/fs/open.c b/fs/open.c
index 806a75d685e1..310b896eecf0 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1015,6 +1015,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
lookup_flags |= LOOKUP_DIRECTORY;
if (!(flags & O_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
+ if (flags & O_EMPTYPATH)
+ lookup_flags |= LOOKUP_EMPTY;
op->lookup_flags = lookup_flags;
return 0;
}
@@ -1076,14 +1078,17 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_flags op;
int fd = build_open_flags(flags, mode, &op);
+ int empty = 0;
struct filename *tmp;
if (fd)
return fd;
- tmp = getname(filename);
+ tmp = getname_flags(filename, op.lookup_flags, &empty);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
+ if (!empty)
+ op.open_flag &= ~O_EMPTYPATH;
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index d019df946cb2..2868ae6c8fc1 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -9,7 +9,7 @@
(O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \
O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \
FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
- O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE)
+ O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_EMPTYPATH)
#ifndef force_o_largefile
#define force_o_largefile() (!IS_ENABLED(CONFIG_ARCH_32BIT_OFF_T))
diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h
index 9dc0bf0c5a6e..ae6862f69cc2 100644
--- a/include/uapi/asm-generic/fcntl.h
+++ b/include/uapi/asm-generic/fcntl.h
@@ -89,6 +89,10 @@
#define __O_TMPFILE 020000000
#endif
+#ifndef O_EMPTYPATH
+#define O_EMPTYPATH 040000000
+#endif
+
/* a horrid kludge trying to make sure that this will fail on old kernels */
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH RESEND v11 2/8] procfs: switch magic-link modes to be more sane
From: Aleksa Sarai @ 2019-08-20 3:34 UTC (permalink / raw)
To: Al Viro, Jeff Layton, J. Bruce Fields, Arnd Bergmann,
David Howells, Shuah Khan, Shuah Khan
Cc: linux-ia64, linux-sh, Alexei Starovoitov, Oleg Nesterov,
linux-kselftest, sparclinux, linux-arch, linux-s390,
Tycho Andersen, Aleksa Sarai, linux-arm-kernel, linux-mips,
linux-xtensa, Kees Cook, Jann Horn, linuxppc-dev, Aleksa Sarai,
Andy Lutomirski, David Drysdale, Christian Brauner, linux-parisc,
linux-m68k, linux-api, Chanho Min, linux-kernel, Eric Biederman,
linux-alpha, linux-fsdevel, Andrew Morton, Linus Torvalds,
containers
In-Reply-To: <20190820033406.29796-1-cyphar@cyphar.com>
Now that magic-link modes are obeyed for file re-opening purposes, some
of the pre-existing magic-link modes need to be adjusted to be more
semantically correct.
The most blatant example of this is /proc/self/exe, which had a mode of
a+rwx even though tautologically the file could never be opened for
writing (because it is the current->mm of a live process).
With the new O_PATH restrictions, changing the default mode of these
magic-links allows us to avoid delayed-access attacks such as we saw in
CVE-2019-5736.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
fs/proc/base.c | 20 ++++++++++----------
fs/proc/namespaces.c | 2 +-
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index ebea9501afb8..297242174402 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -133,9 +133,9 @@ struct pid_entry {
#define DIR(NAME, MODE, iops, fops) \
NOD(NAME, (S_IFDIR|(MODE)), &iops, &fops, {} )
-#define LNK(NAME, get_link) \
- NOD(NAME, (S_IFLNK|S_IRWXUGO), \
- &proc_pid_link_inode_operations, NULL, \
+#define LNK(NAME, MODE, get_link) \
+ NOD(NAME, (S_IFLNK|(MODE)), \
+ &proc_pid_link_inode_operations, NULL, \
{ .proc_get_link = get_link } )
#define REG(NAME, MODE, fops) \
NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {})
@@ -3028,9 +3028,9 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations),
#endif
REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
- LNK("cwd", proc_cwd_link),
- LNK("root", proc_root_link),
- LNK("exe", proc_exe_link),
+ LNK("cwd", S_IRWXUGO, proc_cwd_link),
+ LNK("root", S_IRWXUGO, proc_root_link),
+ LNK("exe", S_IRUGO|S_IXUGO, proc_exe_link),
REG("mounts", S_IRUGO, proc_mounts_operations),
REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
REG("mountstats", S_IRUSR, proc_mountstats_operations),
@@ -3429,11 +3429,11 @@ static const struct pid_entry tid_base_stuff[] = {
REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations),
#endif
REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
- LNK("cwd", proc_cwd_link),
- LNK("root", proc_root_link),
- LNK("exe", proc_exe_link),
+ LNK("cwd", S_IRWXUGO, proc_cwd_link),
+ LNK("root", S_IRWXUGO, proc_root_link),
+ LNK("exe", S_IRUGO|S_IXUGO, proc_exe_link),
REG("mounts", S_IRUGO, proc_mounts_operations),
- REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
+ REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
#ifdef CONFIG_PROC_PAGE_MONITOR
REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
REG("smaps", S_IRUGO, proc_pid_smaps_operations),
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index dd2b35f78b09..cd1e130913f7 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -94,7 +94,7 @@ static struct dentry *proc_ns_instantiate(struct dentry *dentry,
struct inode *inode;
struct proc_inode *ei;
- inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK | S_IRWXUGO);
+ inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK | S_IRUGO);
if (!inode)
return ERR_PTR(-ENOENT);
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH RESEND v11 1/8] namei: obey trailing magic-link DAC permissions
From: Aleksa Sarai @ 2019-08-20 3:33 UTC (permalink / raw)
To: Al Viro, Jeff Layton, J. Bruce Fields, Arnd Bergmann,
David Howells, Shuah Khan, Shuah Khan
Cc: linux-ia64, linux-sh, Alexei Starovoitov, Oleg Nesterov,
linux-kselftest, sparclinux, linux-arch, linux-s390,
Tycho Andersen, Aleksa Sarai, linux-arm-kernel, linux-mips,
linux-xtensa, Kees Cook, Jann Horn, linuxppc-dev, Aleksa Sarai,
Andy Lutomirski, David Drysdale, Christian Brauner, linux-parisc,
linux-m68k, linux-api, Chanho Min, linux-kernel, Eric Biederman,
linux-alpha, linux-fsdevel, Andrew Morton, Linus Torvalds,
containers
In-Reply-To: <20190820033406.29796-1-cyphar@cyphar.com>
The ability for userspace to "re-open" file descriptors through
/proc/self/fd has been a very useful tool for all sorts of usecases
(container runtimes are one common example). However, the current
interface for doing this has resulted in some pretty subtle security
holes. Userspace can re-open a file descriptor with more permissions
than the original, which can result in cases such as /proc/$pid/exe
being re-opened O_RDWR at a later date even though (by definition)
/proc/$pid/exe cannot be opened for writing. When combined with O_PATH
the results can get even more confusing.
We cannot block this outright. Aside from userspace already depending on
it, it's a useful feature which can actually increase the security of
userspace. For instance, LXC keeps an O_PATH of the container's
/dev/pts/ptmx that gets re-opened to create new ptys and then uses
TIOCGPTPEER to get the slave end. This allows for pty allocation without
resolving paths inside an (untrusted) container's rootfs. There isn't a
trivial way of doing this that is as straight-forward and safe as O_PATH
re-opening.
Instead we have to restrict it in such a way that it doesn't break
(good) users but does block potential attackers. The solution applied in
this patch is to restrict *re-opening* (not resolution through)
magic-links by requiring that mode of the link be obeyed. Normal
symlinks have modes of a+rwx but magic-links have other modes. These
magic-link modes were historically ignored during path resolution, but
they've now been re-purposed for more useful ends.
It is also necessary to define semantics for the mode of an O_PATH
descriptor, since re-opening a magic-link through an O_PATH needs to be
just as restricted as the corresponding magic-link -- otherwise the
above protection can be bypassed. There are two distinct cases:
1. The target is a regular file (not a magic-link). Userspace depends
on being able to re-open the O_PATH of a regular file, so we must
define the mode to be a+rwx.
2. The target is a magic-link. In this case, we simply copy the mode of
the magic-link. This results in an O_PATH of a magic-link
effectively acting as a no-op in terms of how much re-opening
privileges a process has.
CAP_DAC_OVERRIDE can be used to override all of these restrictions, but
we only permit &init_userns's capabilities to affect these semantics.
The reason for this is that there isn't a clear way to track what
user_ns is the original owner of a given O_PATH chain -- thus an
unprivileged user could create a new userns and O_PATH the file
descriptor, owning it. All signs would indicate that the user really
does have CAP_DAC_OVERRIDE over the new descriptor and the protection
would be bypassed. We thus opt for the more conservative approach.
I have run this patch on several machines for several days. So far, the
only processes which have hit this case ("loadkeys" and "kbd_mode" from
the kbd package[1]) gracefully handle the permission error and do not
cause any user-visible problems. In order to give users a heads-up, a
warning is output to dmesg whenever may_open_magiclink() refuses access.
[1]: http://git.altlinux.org/people/legion/packages/kbd.git
Suggested-by: Andy Lutomirski <luto@kernel.org>
Suggested-by: Christian Brauner <christian@brauner.io>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
Documentation/filesystems/path-lookup.rst | 12 +--
fs/internal.h | 1 +
fs/namei.c | 105 +++++++++++++++++++---
fs/open.c | 3 +-
fs/proc/fd.c | 23 ++++-
include/linux/fs.h | 4 +
include/linux/namei.h | 1 +
7 files changed, 130 insertions(+), 19 deletions(-)
diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst
index 434a07b0002b..a57d78ec8bee 100644
--- a/Documentation/filesystems/path-lookup.rst
+++ b/Documentation/filesystems/path-lookup.rst
@@ -1310,12 +1310,14 @@ longer needed.
``LOOKUP_JUMPED`` means that the current dentry was chosen not because
it had the right name but for some other reason. This happens when
following "``..``", following a symlink to ``/``, crossing a mount point
-or accessing a "``/proc/$PID/fd/$FD``" symlink. In this case the
-filesystem has not been asked to revalidate the name (with
-``d_revalidate()``). In such cases the inode may still need to be
-revalidated, so ``d_op->d_weak_revalidate()`` is called if
+or accessing a "``/proc/$PID/fd/$FD``" symlink (also known as a "magic
+link"). In this case the filesystem has not been asked to revalidate the
+name (with ``d_revalidate()``). In such cases the inode may still need
+to be revalidated, so ``d_op->d_weak_revalidate()`` is called if
``LOOKUP_JUMPED`` is set when the look completes - which may be at the
-final component or, when creating, unlinking, or renaming, at the penultimate component.
+final component or, when creating, unlinking, or renaming, at the
+penultimate component. ``LOOKUP_MAGICLINK_JUMPED`` is set alongside
+``LOOKUP_JUMPED`` if a magic-link was traversed.
Final-component flags
~~~~~~~~~~~~~~~~~~~~~
diff --git a/fs/internal.h b/fs/internal.h
index 315fcd8d237c..f48449a43626 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -119,6 +119,7 @@ struct open_flags {
int acc_mode;
int intent;
int lookup_flags;
+ fmode_t opath_mask;
};
extern struct file *do_filp_open(int dfd, struct filename *pathname,
const struct open_flags *op);
diff --git a/fs/namei.c b/fs/namei.c
index 209c51a5226c..54d57dad0f91 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -872,7 +872,7 @@ void nd_jump_link(struct path *path)
nd->path = *path;
nd->inode = nd->path.dentry->d_inode;
- nd->flags |= LOOKUP_JUMPED;
+ nd->flags |= LOOKUP_JUMPED | LOOKUP_MAGICLINK_JUMPED;
}
static inline void put_link(struct nameidata *nd)
@@ -1066,6 +1066,7 @@ const char *get_link(struct nameidata *nd)
return ERR_PTR(error);
nd->last_type = LAST_BIND;
+ nd->flags &= ~LOOKUP_MAGICLINK_JUMPED;
res = READ_ONCE(inode->i_link);
if (!res) {
const char * (*get)(struct dentry *, struct inode *,
@@ -3501,16 +3502,73 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
return error;
}
-static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file)
+/**
+ * may_reopen_magiclink - Check permissions for opening a trailing magic-link
+ * @upgrade_mask: the upgrade-mask of the magic-link
+ * @acc_mode: ACC_MODE which the user is attempting
+ *
+ * We block magic-link re-opening if the @upgrade_mask is more strict than the
+ * @acc_mode being requested, unless the user is capable(CAP_DAC_OVERRIDE).
+ *
+ * Returns 0 if successful, -EACCES on error.
+ */
+static int may_open_magiclink(fmode_t upgrade_mask, int acc_mode)
{
- struct path path;
- int error = path_lookupat(nd, flags, &path);
- if (!error) {
- audit_inode(nd->name, path.dentry, 0);
- error = vfs_open(&path, file);
- path_put(&path);
- }
- return error;
+ /*
+ * We only allow for init_userns to be able to override magic-links.
+ * This is done to avoid cases where an unprivileged userns could take
+ * an O_PATH of the fd, resulting in it being very unclear whether
+ * CAP_DAC_OVERRIDE should work on the new O_PATH fd (given that it
+ * pipes through to the underlying file).
+ */
+ if (capable(CAP_DAC_OVERRIDE))
+ return 0;
+
+ if ((acc_mode & MAY_READ) &&
+ !(upgrade_mask & (FMODE_READ | FMODE_PATH_READ)))
+ goto err;
+ if ((acc_mode & MAY_WRITE) &&
+ !(upgrade_mask & (FMODE_WRITE | FMODE_PATH_WRITE)))
+ goto err;
+
+ return 0;
+
+err:
+ pr_warn_ratelimited("%s[%d]: magic-link re-open blocked ('%s%s%s' requested with an upgrade-mask of '%s%s%s%s')",
+ current->comm, task_pid_nr(current),
+ (acc_mode & MAY_READ) ? "r" : "",
+ (acc_mode & MAY_WRITE) ? "w" : "",
+ (acc_mode & MAY_EXEC) ? "x" : "",
+ (upgrade_mask & FMODE_READ) ? "r" : "",
+ (upgrade_mask & FMODE_PATH_READ) ? "R" : "",
+ (upgrade_mask & FMODE_WRITE) ? "w" : "",
+ (upgrade_mask & FMODE_PATH_WRITE) ? "W" : "");
+ return -EACCES;
+}
+
+static int trailing_magiclink(struct nameidata *nd, int acc_mode,
+ fmode_t *opath_mask)
+{
+ struct inode *inode = nd->link_inode;
+ fmode_t upgrade_mask = 0;
+
+ /* Was the trailing_symlink() a magic-link? */
+ if (!(nd->flags & LOOKUP_MAGICLINK_JUMPED))
+ return 0;
+
+ /*
+ * Figure out the upgrade-mask of the link_inode. Since these aren't
+ * strictly POSIX semantics we don't do an acl_permission_check() here,
+ * so we only care that at least one bit is set for each upgrade-mode.
+ */
+ if (inode->i_mode & S_IRUGO)
+ upgrade_mask |= FMODE_PATH_READ;
+ if (inode->i_mode & S_IWUGO)
+ upgrade_mask |= FMODE_PATH_WRITE;
+ /* Restrict the O_PATH upgrade-mask of the caller. */
+ if (opath_mask)
+ *opath_mask &= upgrade_mask;
+ return may_open_magiclink(upgrade_mask, acc_mode);
}
static struct file *path_openat(struct nameidata *nd,
@@ -3526,13 +3584,38 @@ static struct file *path_openat(struct nameidata *nd,
if (unlikely(file->f_flags & __O_TMPFILE)) {
error = do_tmpfile(nd, flags, op, file);
} else if (unlikely(file->f_flags & O_PATH)) {
- error = do_o_path(nd, flags, file);
+ /* Inlined path_lookupat() with a trailing_magiclink() check. */
+ fmode_t opath_mask = op->opath_mask;
+ const char *s = path_init(nd, flags);
+
+ while (!(error = link_path_walk(s, nd))
+ && ((error = lookup_last(nd)) > 0)) {
+ s = trailing_symlink(nd);
+ error = trailing_magiclink(nd, op->acc_mode, &opath_mask);
+ if (error)
+ s = ERR_PTR(error);
+ }
+ if (!error)
+ error = complete_walk(nd);
+
+ if (!error && nd->flags & LOOKUP_DIRECTORY)
+ if (!d_can_lookup(nd->path.dentry))
+ error = -ENOTDIR;
+ if (!error) {
+ audit_inode(nd->name, nd->path.dentry, 0);
+ error = vfs_open(&nd->path, file);
+ file->f_mode |= opath_mask;
+ }
+ terminate_walk(nd);
} else {
const char *s = path_init(nd, flags);
while (!(error = link_path_walk(s, nd)) &&
(error = do_last(nd, file, op)) > 0) {
nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
s = trailing_symlink(nd);
+ error = trailing_magiclink(nd, op->acc_mode, NULL);
+ if (error)
+ s = ERR_PTR(error);
}
terminate_walk(nd);
}
diff --git a/fs/open.c b/fs/open.c
index a59abe3c669a..806a75d685e1 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1001,8 +1001,9 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
acc_mode |= MAY_APPEND;
op->acc_mode = acc_mode;
-
op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;
+ /* For O_PATH backwards-compatibility we default to an all-set mask. */
+ op->opath_mask = FMODE_PATH_READ | FMODE_PATH_WRITE;
if (flags & O_CREAT) {
op->intent |= LOOKUP_CREATE;
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 81882a13212d..9b7d8becb002 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -104,11 +104,30 @@ static void tid_fd_update_inode(struct task_struct *task, struct inode *inode,
task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);
if (S_ISLNK(inode->i_mode)) {
+ /*
+ * Always set +x (depending on the fmode type), since there
+ * currently aren't FMODE_PATH_EXEC restrictions and there is
+ * no O_MAYEXEC yet. This might change in the future, in which
+ * case we will restrict +x.
+ */
unsigned i_mode = S_IFLNK;
+ if (f_mode & FMODE_PATH)
+ i_mode |= S_IXGRP;
+ else
+ i_mode |= S_IXUSR;
+ /*
+ * Construct the mode bits based on the open-mode. The u+rwx
+ * bits are for "ordinary" open modes while g+rwx are for
+ * O_PATH modes.
+ */
if (f_mode & FMODE_READ)
- i_mode |= S_IRUSR | S_IXUSR;
+ i_mode |= S_IRUSR;
if (f_mode & FMODE_WRITE)
- i_mode |= S_IWUSR | S_IXUSR;
+ i_mode |= S_IWUSR;
+ if (f_mode & FMODE_PATH_READ)
+ i_mode |= S_IRGRP;
+ if (f_mode & FMODE_PATH_WRITE)
+ i_mode |= S_IWGRP;
inode->i_mode = i_mode;
}
security_task_to_inode(task, inode);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 997a530ff4e9..a9ad596b28e2 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -173,6 +173,10 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
/* File does not contribute to nr_files count */
#define FMODE_NOACCOUNT ((__force fmode_t)0x20000000)
+/* File is an O_PATH descriptor which can be upgraded to (read, write). */
+#define FMODE_PATH_READ ((__force fmode_t)0x40000000)
+#define FMODE_PATH_WRITE ((__force fmode_t)0x80000000)
+
/*
* Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector
* that indicates that they should check the contents of the iovec are
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 9138b4471dbf..bd6d3eb7764d 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -49,6 +49,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_ROOT 0x2000
#define LOOKUP_EMPTY 0x4000
#define LOOKUP_DOWN 0x8000
+#define LOOKUP_MAGICLINK_JUMPED 0x10000
extern int path_pts(struct path *path);
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH RESEND v11 0/8] openat2(2)
From: Aleksa Sarai @ 2019-08-20 3:33 UTC (permalink / raw)
To: Al Viro, Jeff Layton, J. Bruce Fields, Arnd Bergmann,
David Howells, Shuah Khan, Shuah Khan
Cc: linux-ia64, linux-sh, Alexei Starovoitov, Oleg Nesterov,
linux-kselftest, sparclinux, linux-arch, linux-s390,
Tycho Andersen, Aleksa Sarai, linux-arm-kernel, linux-mips,
linux-xtensa, Kees Cook, Jann Horn, linuxppc-dev, Aleksa Sarai,
Andy Lutomirski, David Drysdale, Christian Brauner, linux-parisc,
linux-m68k, linux-api, containers, linux-kernel, Eric Biederman,
linux-alpha, linux-fsdevel, Andrew Morton, Linus Torvalds,
Chanho Min
This patchset is being developed here:
<https://github.com/cyphar/linux/tree/resolveat/master>
Patch changelog:
v11: [RESEND: <https://lore.kernel.org/lkml/20190728010207.9781-1-cyphar@cyphar.com/>]
* Fix checkpatch.pl errors and warnings where reasonable.
* Minor cleanup to pr_warn logging for may_open_magiclink().
* Drop kselftests patch to handle %m formatting correctly, and send
it through the kselftests tree directly. [Shuah Khan]
v10: <https://lore.kernel.org/lkml/20190719164225.27083-1-cyphar@cyphar.com/>
v09: <https://lore.kernel.org/lkml/20190706145737.5299-1-cyphar@cyphar.com/>
v08: <https://lore.kernel.org/lkml/20190520133305.11925-1-cyphar@cyphar.com/>
v07: <https://lore.kernel.org/lkml/20190507164317.13562-1-cyphar@cyphar.com/>
v06: <https://lore.kernel.org/lkml/20190506165439.9155-1-cyphar@cyphar.com/>
v05: <https://lore.kernel.org/lkml/20190320143717.2523-1-cyphar@cyphar.com/>
v04: <https://lore.kernel.org/lkml/20181112142654.341-1-cyphar@cyphar.com/>
v03: <https://lore.kernel.org/lkml/20181009070230.12884-1-cyphar@cyphar.com/>
v02: <https://lore.kernel.org/lkml/20181009065300.11053-1-cyphar@cyphar.com/>
v01: <https://lore.kernel.org/lkml/20180929103453.12025-1-cyphar@cyphar.com/>
The need for some sort of control over VFS's path resolution (to avoid
malicious paths resulting in inadvertent breakouts) has been a very
long-standing desire of many userspace applications. This patchset is a
revival of Al Viro's old AT_NO_JUMPS[1,2] patchset (which was a variant
of David Drysdale's O_BENEATH patchset[3] which was a spin-off of the
Capsicum project[4]) with a few additions and changes made based on the
previous discussion within [5] as well as others I felt were useful.
In line with the conclusions of the original discussion of AT_NO_JUMPS,
the flag has been split up into separate flags. However, instead of
being an openat(2) flag it is provided through a new syscall openat2(2)
which provides several other improvements to the openat(2) interface (see the
patch description for more details). The following new LOOKUP_* flags are
added:
* LOOKUP_NO_XDEV blocks all mountpoint crossings (upwards, downwards,
or through absolute links). Absolute pathnames alone in openat(2) do
not trigger this.
* LOOKUP_NO_MAGICLINKS blocks resolution through /proc/$pid/fd-style
links. This is done by blocking the usage of nd_jump_link() during
resolution in a filesystem. The term "magic-links" is used to match
with the only reference to these links in Documentation/, but I'm
happy to change the name.
It should be noted that this is different to the scope of
~LOOKUP_FOLLOW in that it applies to all path components. However,
you can do openat2(NO_FOLLOW|NO_MAGICLINKS) on a magic-link and it
will *not* fail (assuming that no parent component was a
magic-link), and you will have an fd for the magic-link.
* LOOKUP_BENEATH disallows escapes to outside the starting dirfd's
tree, using techniques such as ".." or absolute links. Absolute
paths in openat(2) are also disallowed. Conceptually this flag is to
ensure you "stay below" a certain point in the filesystem tree --
but this requires some additional to protect against various races
that would allow escape using "..".
Currently LOOKUP_BENEATH implies LOOKUP_NO_MAGICLINKS, because it
can trivially beam you around the filesystem (breaking the
protection). In future, there might be similar safety checks done as
in LOOKUP_IN_ROOT, but that requires more discussion.
In addition, two new flags are added that expand on the above ideas:
* LOOKUP_NO_SYMLINKS does what it says on the tin. No symlink
resolution is allowed at all, including magic-links. Just as with
LOOKUP_NO_MAGICLINKS this can still be used with NOFOLLOW to open an
fd for the symlink as long as no parent path had a symlink
component.
* LOOKUP_IN_ROOT is an extension of LOOKUP_BENEATH that, rather than
blocking attempts to move past the root, forces all such movements
to be scoped to the starting point. This provides chroot(2)-like
protection but without the cost of a chroot(2) for each filesystem
operation, as well as being safe against race attacks that chroot(2)
is not.
If a race is detected (as with LOOKUP_BENEATH) then an error is
generated, and similar to LOOKUP_BENEATH it is not permitted to cross
magic-links with LOOKUP_IN_ROOT.
The primary need for this is from container runtimes, which
currently need to do symlink scoping in userspace[6] when opening
paths in a potentially malicious container. There is a long list of
CVEs that could have bene mitigated by having RESOLVE_THIS_ROOT
(such as CVE-2017-1002101, CVE-2017-1002102, CVE-2018-15664, and
CVE-2019-5736, just to name a few).
And further, several semantics of file descriptor "re-opening" are now
changed to prevent attacks like CVE-2019-5736 by restricting how
magic-links can be resolved (based on their mode). This required some
other changes to the semantics of the modes of O_PATH file descriptor's
associated /proc/self/fd magic-links. openat2(2) has the ability to
further restrict re-opening of its own O_PATH fds, so that users can
make even better use of this feature.
Finally, O_EMPTYPATH was added so that users can do /proc/self/fd-style
re-opening without depending on procfs. The new restricted semantics for
magic-links are applied here too.
In order to make all of the above more usable, I'm working on
libpathrs[7] which is a C-friendly library for safe path resolution. It
features a userspace-emulated backend if the kernel doesn't support
openat2(2). Hopefully we can get userspace to switch to using it, and
thus get openat2(2) support for free once it's ready.
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Christian Brauner <christian@brauner.io>
Cc: David Drysdale <drysdale@google.com>
Cc: Tycho Andersen <tycho@tycho.ws>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: <containers@lists.linux-foundation.org>
Cc: <linux-fsdevel@vger.kernel.org>
Cc: <linux-api@vger.kernel.org>
[1]: https://lwn.net/Articles/721443/
[2]: https://lore.kernel.org/patchwork/patch/784221/
[3]: https://lwn.net/Articles/619151/
[4]: https://lwn.net/Articles/603929/
[5]: https://lwn.net/Articles/723057/
[6]: https://github.com/cyphar/filepath-securejoin
[7]: https://github.com/openSUSE/libpathrs
Aleksa Sarai (8):
namei: obey trailing magic-link DAC permissions
procfs: switch magic-link modes to be more sane
open: O_EMPTYPATH: procfs-less file descriptor re-opening
namei: O_BENEATH-style path resolution flags
namei: LOOKUP_IN_ROOT: chroot-like path resolution
namei: aggressively check for nd->root escape on ".." resolution
open: openat2(2) syscall
selftests: add openat2(2) selftests
Documentation/filesystems/path-lookup.rst | 12 +-
arch/alpha/include/uapi/asm/fcntl.h | 1 +
arch/alpha/kernel/syscalls/syscall.tbl | 1 +
arch/arm/tools/syscall.tbl | 1 +
arch/arm64/include/asm/unistd.h | 2 +-
arch/arm64/include/asm/unistd32.h | 2 +
arch/ia64/kernel/syscalls/syscall.tbl | 1 +
arch/m68k/kernel/syscalls/syscall.tbl | 1 +
arch/microblaze/kernel/syscalls/syscall.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n32.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n64.tbl | 1 +
arch/mips/kernel/syscalls/syscall_o32.tbl | 1 +
arch/parisc/include/uapi/asm/fcntl.h | 39 +-
arch/parisc/kernel/syscalls/syscall.tbl | 1 +
arch/powerpc/kernel/syscalls/syscall.tbl | 1 +
arch/s390/kernel/syscalls/syscall.tbl | 1 +
arch/sh/kernel/syscalls/syscall.tbl | 1 +
arch/sparc/include/uapi/asm/fcntl.h | 1 +
arch/sparc/kernel/syscalls/syscall.tbl | 1 +
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
arch/xtensa/kernel/syscalls/syscall.tbl | 1 +
fs/fcntl.c | 2 +-
fs/internal.h | 1 +
fs/namei.c | 270 ++++++++++--
fs/open.c | 112 ++++-
fs/proc/base.c | 20 +-
fs/proc/fd.c | 23 +-
fs/proc/namespaces.c | 2 +-
include/linux/fcntl.h | 17 +-
include/linux/fs.h | 8 +-
include/linux/namei.h | 9 +
include/linux/syscalls.h | 17 +-
include/uapi/asm-generic/fcntl.h | 4 +
include/uapi/asm-generic/unistd.h | 5 +-
include/uapi/linux/fcntl.h | 42 ++
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/memfd/memfd_test.c | 7 +-
tools/testing/selftests/openat2/.gitignore | 1 +
tools/testing/selftests/openat2/Makefile | 8 +
tools/testing/selftests/openat2/helpers.c | 162 +++++++
tools/testing/selftests/openat2/helpers.h | 116 +++++
.../testing/selftests/openat2/linkmode_test.c | 333 +++++++++++++++
.../selftests/openat2/rename_attack_test.c | 127 ++++++
.../testing/selftests/openat2/resolve_test.c | 402 ++++++++++++++++++
45 files changed, 1655 insertions(+), 107 deletions(-)
create mode 100644 tools/testing/selftests/openat2/.gitignore
create mode 100644 tools/testing/selftests/openat2/Makefile
create mode 100644 tools/testing/selftests/openat2/helpers.c
create mode 100644 tools/testing/selftests/openat2/helpers.h
create mode 100644 tools/testing/selftests/openat2/linkmode_test.c
create mode 100644 tools/testing/selftests/openat2/rename_attack_test.c
create mode 100644 tools/testing/selftests/openat2/resolve_test.c
--
2.22.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v4 10/10] [DO NOT MERGE] drivers: firmware: msgbox demo
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
This driver provides a trivial mailbox client that can be used with the
mailbox-demo branch of https://github.com/crust-firmware/crust for
verifying the functionality of the sunxi-msgbox driver.
This is not a "real" driver, nor a "real" firmware protocol. This driver
is not intended to be merged. It is provided only as an example that
won't interfere with any other hardware.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 24 ++
arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi | 24 ++
drivers/firmware/Kconfig | 6 +
drivers/firmware/Makefile | 1 +
drivers/firmware/sunxi_msgbox_demo.c | 310 ++++++++++++++++++
5 files changed, 365 insertions(+)
create mode 100644 drivers/firmware/sunxi_msgbox_demo.c
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 428f539a091a..78315d5512db 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -121,6 +121,30 @@
};
};
+ demo_0 {
+ compatible = "allwinner,sunxi-msgbox-demo";
+ mboxes = <&msgbox 0>, <&msgbox 1>;
+ mbox-names = "tx", "rx";
+ };
+
+ demo_1 {
+ compatible = "allwinner,sunxi-msgbox-demo";
+ mboxes = <&msgbox 2>, <&msgbox 3>;
+ mbox-names = "tx", "rx";
+ };
+
+ demo_2 {
+ compatible = "allwinner,sunxi-msgbox-demo";
+ mboxes = <&msgbox 4>, <&msgbox 5>;
+ mbox-names = "tx", "rx";
+ };
+
+ demo_3 {
+ compatible = "allwinner,sunxi-msgbox-demo";
+ mboxes = <&msgbox 6>, <&msgbox 7>;
+ mbox-names = "tx", "rx";
+ };
+
de: display-engine {
compatible = "allwinner,sun50i-a64-display-engine";
allwinner,pipelines = <&mixer0>,
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
index f002a496d7cb..5a2d85b7e0a1 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
@@ -76,6 +76,30 @@
};
};
+ demo_0 {
+ compatible = "allwinner,sunxi-msgbox-demo";
+ mboxes = <&msgbox 0>, <&msgbox 1>;
+ mbox-names = "tx", "rx";
+ };
+
+ demo_1 {
+ compatible = "allwinner,sunxi-msgbox-demo";
+ mboxes = <&msgbox 2>, <&msgbox 3>;
+ mbox-names = "tx", "rx";
+ };
+
+ demo_2 {
+ compatible = "allwinner,sunxi-msgbox-demo";
+ mboxes = <&msgbox 4>, <&msgbox 5>;
+ mbox-names = "tx", "rx";
+ };
+
+ demo_3 {
+ compatible = "allwinner,sunxi-msgbox-demo";
+ mboxes = <&msgbox 6>, <&msgbox 7>;
+ mbox-names = "tx", "rx";
+ };
+
psci {
compatible = "arm,psci-0.2";
method = "smc";
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index ba8d3d0ef32c..e0f8f3c856c1 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -240,6 +240,12 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
Say Y here to enable "download mode" by default.
+config SUNXI_MSGBOX_DEMO
+ tristate "sunxi msgbox demo"
+ depends on MAILBOX
+ help
+ Demo client for demo firmware to use in mailbox driver validation.
+
config TI_SCI_PROTOCOL
tristate "TI System Control Interface (TISCI) Message Protocol"
depends on TI_MESSAGE_MANAGER
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 3fa0b34eb72f..6f8e17a854b6 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
+obj-$(CONFIG_SUNXI_MSGBOX_DEMO) += sunxi_msgbox_demo.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
diff --git a/drivers/firmware/sunxi_msgbox_demo.c b/drivers/firmware/sunxi_msgbox_demo.c
new file mode 100644
index 000000000000..9431b1ef1841
--- /dev/null
+++ b/drivers/firmware/sunxi_msgbox_demo.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2018-2019 Samuel Holland <samuel@sholland.org>
+
+#include <linux/completion.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/random.h>
+
+enum {
+ OP_MAGIC,
+ OP_VERSION,
+ OP_LOOPBACK,
+ OP_LOOPBACK_INVERTED,
+ OP_TIME_SECONDS,
+ OP_TIME_TICKS,
+ OP_DELAY_MICROS,
+ OP_DELAY_MILLIS,
+ OP_ADDR_SET_LO,
+ OP_ADDR_SET_HI,
+ OP_ADDR_READ,
+ OP_ADDR_WRITE,
+ OP_INVALID_1,
+ OP_INVALID_2,
+ OP_RESET = 16,
+};
+
+struct msgbox_demo {
+ struct mbox_chan *rx_chan;
+ struct mbox_chan *tx_chan;
+ struct mbox_client cl;
+ struct completion completion;
+ uint32_t request;
+ uint32_t response;
+ uint32_t address;
+ uint32_t value;
+};
+
+static void msgbox_demo_rx(struct mbox_client *cl, void *msg)
+{
+ struct msgbox_demo *demo = container_of(cl, struct msgbox_demo, cl);
+
+ demo->response = *(uint32_t *)msg;
+ complete(&demo->completion);
+}
+
+static int msgbox_demo_tx(struct msgbox_demo *demo, uint32_t request)
+{
+ unsigned long timeout = msecs_to_jiffies(10);
+ int ret;
+
+ demo->request = request;
+ demo->response = 0;
+ reinit_completion(&demo->completion);
+
+ ret = mbox_send_message(demo->tx_chan, &demo->request);
+ if (ret < 0) {
+ dev_err(demo->cl.dev, "Failed to send request: %d\n", ret);
+ return ret;
+ }
+
+ if (wait_for_completion_timeout(&demo->completion, timeout))
+ return 0;
+
+ return -ETIMEDOUT;
+}
+
+static void msgbox_demo_do_operation(struct msgbox_demo *demo, uint16_t op)
+{
+ struct device *dev = demo->cl.dev;
+ uint16_t data = 0;
+ uint32_t resp = 0;
+ int exp = 0;
+ int ret;
+
+ switch (op) {
+ case OP_MAGIC:
+ resp = 0x1a2a3a4a;
+ break;
+ case OP_LOOPBACK:
+ data = get_random_u32();
+ resp = data;
+ break;
+ case OP_LOOPBACK_INVERTED:
+ data = get_random_u32();
+ resp = ~data;
+ break;
+ case OP_DELAY_MICROS:
+ data = 25000;
+ exp = -ETIMEDOUT;
+ break;
+ case OP_DELAY_MILLIS:
+ data = 500;
+ exp = -ETIMEDOUT;
+ break;
+ case OP_ADDR_SET_LO:
+ data = demo->address & 0xffff;
+ resp = demo->address;
+ break;
+ case OP_ADDR_SET_HI:
+ data = demo->address >> 16;
+ break;
+ case OP_ADDR_WRITE:
+ data = demo->value;
+ resp = demo->value;
+ break;
+ case OP_INVALID_1:
+ case OP_INVALID_2:
+ resp = -1U;
+ break;
+ case OP_RESET:
+ exp = -ETIMEDOUT;
+ break;
+ }
+
+ dev_info(demo->cl.dev, "Sending opcode %d, data 0x%08x\n", op, data);
+ ret = msgbox_demo_tx(demo, op << 16 | data);
+
+ if (ret) {
+ /* Nothing was received. */
+ if (exp)
+ dev_info(dev, "No response received, as expected\n");
+ else
+ dev_err(dev, "Timeout receiving response\n");
+ return;
+ }
+
+ /* Something was received. */
+ if (exp)
+ dev_err(dev, "Unexpected response 0x%08x\n", demo->response);
+ else if (!resp)
+ dev_info(dev, "Received response 0x%08x\n", demo->response);
+ else if (demo->response == resp)
+ dev_info(dev, "Good response 0x%08x\n", resp);
+ else
+ dev_err(dev, "Expected 0x%08x, received 0x%08x\n",
+ resp, demo->response);
+}
+
+ssize_t demo_address_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct msgbox_demo *demo = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%08x\n", demo->address);
+}
+
+static ssize_t demo_address_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct msgbox_demo *demo = dev_get_drvdata(dev);
+ uint32_t val;
+
+ if (sscanf(buf, "%x", &val)) {
+ demo->address = val;
+ msgbox_demo_do_operation(demo, OP_ADDR_SET_HI);
+ msgbox_demo_do_operation(demo, OP_ADDR_SET_LO);
+ return count;
+ }
+
+ return 0;
+}
+
+ssize_t demo_value_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct msgbox_demo *demo = dev_get_drvdata(dev);
+
+ msgbox_demo_do_operation(demo, OP_ADDR_READ);
+ demo->value = demo->response;
+
+ return sprintf(buf, "%08x\n", demo->value);
+}
+
+static ssize_t demo_value_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct msgbox_demo *demo = dev_get_drvdata(dev);
+ int16_t val;
+
+ if (sscanf(buf, "%hx", &val)) {
+ demo->value = (int32_t)val;
+ msgbox_demo_do_operation(demo, OP_ADDR_WRITE);
+ return count;
+ }
+
+ return 0;
+}
+
+static ssize_t demo_operation_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct msgbox_demo *demo = dev_get_drvdata(dev);
+ uint16_t val;
+
+ if (sscanf(buf, "%hu", &val)) {
+ msgbox_demo_do_operation(demo, val);
+ return count;
+ }
+
+ return 0;
+}
+
+static DEVICE_ATTR(demo_address, 0644, demo_address_show, demo_address_store);
+static DEVICE_ATTR(demo_value, 0644, demo_value_show, demo_value_store);
+static DEVICE_ATTR(demo_operation, 0200, NULL, demo_operation_store);
+
+static int msgbox_demo_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_attribute *attr;
+ struct msgbox_demo *demo;
+ int ret;
+
+ demo = devm_kzalloc(dev, sizeof(*demo), GFP_KERNEL);
+ if (!demo)
+ return -ENOMEM;
+
+ demo->cl.dev = dev;
+ demo->cl.rx_callback = msgbox_demo_rx;
+
+ if (of_get_property(dev->of_node, "mbox-names", NULL)) {
+ demo->rx_chan = mbox_request_channel_byname(&demo->cl, "rx");
+ if (IS_ERR(demo->rx_chan)) {
+ ret = PTR_ERR(demo->rx_chan);
+ dev_err(dev, "Failed to request rx mailbox channel\n");
+ goto err;
+ }
+ demo->tx_chan = mbox_request_channel_byname(&demo->cl, "tx");
+ if (IS_ERR(demo->tx_chan)) {
+ ret = PTR_ERR(demo->tx_chan);
+ dev_err(dev, "Failed to request tx mailbox channel\n");
+ goto err_free_rx_chan;
+ }
+ } else {
+ demo->rx_chan = mbox_request_channel(&demo->cl, 0);
+ demo->tx_chan = demo->rx_chan;
+ if (IS_ERR(demo->tx_chan)) {
+ ret = PTR_ERR(demo->tx_chan);
+ dev_err(dev, "Failed to request mailbox channel\n");
+ goto err;
+ }
+ }
+
+ attr = &dev_attr_demo_address;
+ ret = device_create_file(dev, attr);
+ if (ret)
+ goto err_creating_files;
+ attr = &dev_attr_demo_value;
+ ret = device_create_file(dev, attr);
+ if (ret)
+ goto err_creating_files;
+ attr = &dev_attr_demo_operation;
+ ret = device_create_file(dev, attr);
+ if (ret)
+ goto err_creating_files;
+
+ init_completion(&demo->completion);
+
+ platform_set_drvdata(pdev, demo);
+
+ msgbox_demo_do_operation(demo, OP_VERSION);
+
+ return 0;
+
+err_creating_files:
+ dev_err(dev, "Failed to create sysfs attribute %s: %d\n",
+ attr->attr.name, ret);
+ if (demo->tx_chan != demo->rx_chan)
+ mbox_free_channel(demo->tx_chan);
+err_free_rx_chan:
+ mbox_free_channel(demo->rx_chan);
+err:
+ return ret;
+}
+
+static int msgbox_demo_remove(struct platform_device *pdev)
+{
+ struct msgbox_demo *demo = platform_get_drvdata(pdev);
+
+ if (demo->tx_chan != demo->rx_chan)
+ mbox_free_channel(demo->tx_chan);
+ mbox_free_channel(demo->rx_chan);
+
+ return 0;
+}
+
+static const struct of_device_id msgbox_demo_of_match[] = {
+ { .compatible = "allwinner,sunxi-msgbox-demo" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, msgbox_demo_of_match);
+
+static struct platform_driver msgbox_demo_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = msgbox_demo_of_match,
+ },
+ .probe = msgbox_demo_probe,
+ .remove = msgbox_demo_remove,
+};
+module_platform_driver(msgbox_demo_driver);
+
+MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
+MODULE_DESCRIPTION("sunxi msgbox demo");
+MODULE_LICENSE("GPL v2");
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 09/10] arm64: dts: allwinner: h6: Add msgbox node
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
The H6 SoC contains a message box that can be used to send messages and
interrupts back and forth between the ARM application CPUs and the ARISC
coprocessor. Add a device tree node for it.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 67b732e34091..2ff6a47e3cbf 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -215,6 +215,16 @@
#dma-cells = <1>;
};
+ msgbox: mailbox@3003000 {
+ compatible = "allwinner,sun50i-h6-msgbox",
+ "allwinner,sun6i-a31-msgbox";
+ reg = <0x03003000 0x1000>;
+ clocks = <&ccu CLK_BUS_MSGBOX>;
+ resets = <&ccu RST_BUS_MSGBOX>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
+ };
+
sid: efuse@3006000 {
compatible = "allwinner,sun50i-h6-sid";
reg = <0x03006000 0x400>;
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 08/10] arm64: dts: allwinner: a64: Add msgbox node
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
The A64 SoC contains a message box that can be used to send messages and
interrupts back and forth between the ARM application CPUs and the ARISC
coprocessor. Add a device tree node for it.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index ddb6f11e89df..428f539a091a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -487,6 +487,16 @@
reg = <0x1c14000 0x400>;
};
+ msgbox: mailbox@1c17000 {
+ compatible = "allwinner,sun50i-a64-msgbox",
+ "allwinner,sun6i-a31-msgbox";
+ reg = <0x01c17000 0x1000>;
+ clocks = <&ccu CLK_BUS_MSGBOX>;
+ resets = <&ccu RST_BUS_MSGBOX>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
+ };
+
usb_otg: usb@1c19000 {
compatible = "allwinner,sun8i-a33-musb";
reg = <0x01c19000 0x0400>;
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 07/10] ARM: dts: sunxi: h3/h5: Add msgbox node
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
The H3 and H5 SoCs contain a message box that can be used to send
messages and interrupts back and forth between the ARM application CPUs
and the ARISC coprocessor. Add a device tree node for it.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 224e105a994a..f25876a8021a 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -232,6 +232,16 @@
reg = <0x1c14000 0x400>;
};
+ msgbox: mailbox@1c17000 {
+ compatible = "allwinner,sun8i-h3-msgbox",
+ "allwinner,sun6i-a31-msgbox";
+ reg = <0x01c17000 0x1000>;
+ clocks = <&ccu CLK_BUS_MSGBOX>;
+ resets = <&ccu RST_BUS_MSGBOX>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
+ };
+
usb_otg: usb@1c19000 {
compatible = "allwinner,sun8i-h3-musb";
reg = <0x01c19000 0x400>;
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 05/10] ARM: dts: sunxi: a80: Add msgbox node
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
The A80 SoC contains a message box that can be used to send messages and
interrupts back and forth between the ARM application CPUs and the ARISC
coprocessor. Add a device tree node for it.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
arch/arm/boot/dts/sun9i-a80.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index c34d505c7efe..844a265dbd0e 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -318,6 +318,16 @@
};
};
+ msgbox: mailbox@803000 {
+ compatible = "allwinner,sun9i-a80-msgbox",
+ "allwinner,sun6i-a31-msgbox";
+ reg = <0x00803000 0x1000>;
+ clocks = <&ccu CLK_BUS_MSGBOX>;
+ resets = <&ccu RST_BUS_MSGBOX>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
+ };
+
gmac: ethernet@830000 {
compatible = "allwinner,sun7i-a20-gmac";
reg = <0x00830000 0x1054>;
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 00/10] Allwinner sunxi message box support
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
This series adds support for the "hardware message box" in sun8i, sun9i,
and sun50i SoCs, used for communication with the ARISC management
processor (the platform's equivalent of the ARM SCP). The end goal is to
use the arm_scpi driver as a client, communicating with firmware running
on the AR100 CPU, or to use the mailbox to forward NMIs that the
firmware picks up from R_INTC.
Unfortunately, the ARM SCPI client no longer works with this driver
since it now exposes all 8 hardware FIFOs individually. The SCPI client
could be made to work (and I posted proof-of-concept code to that effect
with v1 of this series), but that is a low priority, as Linux does not
directly use SCPI with the current firmware version; all SCPI use goes
through ATF via PSCI.
As requested in the comments to v3 of this patchset, a demo client is
provided in the final patch. This demo goes along with a toy firmware
which shows that the driver does indeed work for two-way communication
on all channels. To build the firmware component, run:
git clone https://github.com/crust-firmware/meta meta
git clone -b mailbox-demo https://github.com/crust-firmware/crust meta/crust
cd meta
make
That will by default produce a U-Boot + ATF + SCP firmware image in
[meta/]build/pinebook/u-boot-sunxi-with-spl.bin. See the top-level
README.md for more information, such as cross-compiler setup.
I've now used this driver with three separate clients over the past two
years, and they all work. If there are no remaining concerns with the
driver, I'd like it to get merged.
Even without the driver, the clock patches (1-2) can go in at any time.
Changes from v3:
- Rebased on sunxi-next
- Added Rob's Reviewed-by for patch 3
- Fixed a crash when receiving a message on a disabled channel
- Cleaned up some comments/formatting in the driver
- Fixed #mbox-cells in sunxi-h3-h5.dtsi (patch 7)
- Removed the irqchip example (no longer relevant to the fw design)
- Added a demo/example client that uses the driver and a toy firmware
Changes from v2:
- Merge patches 1-3
- Add a comment in the code explaining the CLK_IS_CRITICAL usage
- Add a patch to mark the AR100 clocks as critical
- Use YAML for the device tree binding
- Include a not-for-merge example usage of the mailbox
Changes from v1:
- Marked message box clocks as critical instead of hacks in the driver
- 8 unidirectional channels instead of 4 bidirectional pairs
- Use per-SoC compatible strings and an A31 fallback compatible
- Dropped the mailbox framework patch
- Include DT patches for SoCs that document the message box
Samuel Holland (10):
clk: sunxi-ng: Mark msgbox clocks as critical
clk: sunxi-ng: Mark AR100 clocks as critical
dt-bindings: mailbox: Add a sunxi message box binding
mailbox: sunxi-msgbox: Add a new mailbox driver
ARM: dts: sunxi: a80: Add msgbox node
ARM: dts: sunxi: a83t: Add msgbox node
ARM: dts: sunxi: h3/h5: Add msgbox node
arm64: dts: allwinner: a64: Add msgbox node
arm64: dts: allwinner: h6: Add msgbox node
[DO NOT MERGE] drivers: firmware: msgbox demo
.../mailbox/allwinner,sunxi-msgbox.yaml | 79 +++++
arch/arm/boot/dts/sun8i-a83t.dtsi | 10 +
arch/arm/boot/dts/sun9i-a80.dtsi | 10 +
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 10 +
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 34 ++
arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi | 24 ++
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 10 +
drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 3 +-
drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c | 2 +-
drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 3 +-
drivers/clk/sunxi-ng/ccu-sun8i-a23.c | 3 +-
drivers/clk/sunxi-ng/ccu-sun8i-a33.c | 3 +-
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 3 +-
drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 3 +-
drivers/clk/sunxi-ng/ccu-sun8i-r.c | 2 +-
drivers/clk/sunxi-ng/ccu-sun9i-a80.c | 3 +-
drivers/firmware/Kconfig | 6 +
drivers/firmware/Makefile | 1 +
drivers/firmware/sunxi_msgbox_demo.c | 307 +++++++++++++++++
drivers/mailbox/Kconfig | 10 +
drivers/mailbox/Makefile | 2 +
drivers/mailbox/sunxi-msgbox.c | 323 ++++++++++++++++++
22 files changed, 842 insertions(+), 9 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mailbox/allwinner,sunxi-msgbox.yaml
create mode 100644 drivers/firmware/sunxi_msgbox_demo.c
create mode 100644 drivers/mailbox/sunxi-msgbox.c
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v4 06/10] ARM: dts: sunxi: a83t: Add msgbox node
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
The A83T SoC contains a message box that can be used to send messages
and interrupts back and forth between the ARM application CPUs and the
ARISC coprocessor. Add a device tree node for it.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 523be6611c50..8871d1aaf7f5 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -583,6 +583,16 @@
reg = <0x1c14000 0x400>;
};
+ msgbox: mailbox@1c17000 {
+ compatible = "allwinner,sun8i-a83t-msgbox",
+ "allwinner,sun6i-a31-msgbox";
+ reg = <0x01c17000 0x1000>;
+ clocks = <&ccu CLK_BUS_MSGBOX>;
+ resets = <&ccu RST_BUS_MSGBOX>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
+ };
+
usb_otg: usb@1c19000 {
compatible = "allwinner,sun8i-a83t-musb",
"allwinner,sun8i-a33-musb";
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 04/10] mailbox: sunxi-msgbox: Add a new mailbox driver
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
Allwinner sun8i, sun9i, and sun50i SoCs contain a hardware message box
used for communication between the ARM CPUs and the ARISC management
coprocessor. The hardware contains 8 unidirectional 4-message FIFOs.
Add a driver for it, so it can be used for SCPI or other communication
protocols.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
drivers/mailbox/Kconfig | 10 +
drivers/mailbox/Makefile | 2 +
drivers/mailbox/sunxi-msgbox.c | 323 +++++++++++++++++++++++++++++++++
3 files changed, 335 insertions(+)
create mode 100644 drivers/mailbox/sunxi-msgbox.c
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index ab4eb750bbdd..57d12936175e 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -227,4 +227,14 @@ config ZYNQMP_IPI_MBOX
message to the IPI buffer and will access the IPI control
registers to kick the other processor or enquire status.
+config SUNXI_MSGBOX
+ tristate "Allwinner sunxi Message Box"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ default ARCH_SUNXI
+ help
+ Mailbox implementation for the hardware message box present in
+ Allwinner sun8i, sun9i, and sun50i SoCs. The hardware message box is
+ used for communication between the application CPUs and the power
+ management coprocessor.
+
endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index c22fad6f696b..bec2d50b0976 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -48,3 +48,5 @@ obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o
obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o
obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o
+
+obj-$(CONFIG_SUNXI_MSGBOX) += sunxi-msgbox.o
diff --git a/drivers/mailbox/sunxi-msgbox.c b/drivers/mailbox/sunxi-msgbox.c
new file mode 100644
index 000000000000..29a5101a5390
--- /dev/null
+++ b/drivers/mailbox/sunxi-msgbox.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2017-2019 Samuel Holland <samuel@sholland.org>
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+
+#define NUM_CHANS 8
+
+#define CTRL_REG(n) (0x0000 + 0x4 * ((n) / 4))
+#define CTRL_RX(n) BIT(0 + 8 * ((n) % 4))
+#define CTRL_TX(n) BIT(4 + 8 * ((n) % 4))
+
+#define REMOTE_IRQ_EN_REG 0x0040
+#define REMOTE_IRQ_STAT_REG 0x0050
+#define LOCAL_IRQ_EN_REG 0x0060
+#define LOCAL_IRQ_STAT_REG 0x0070
+
+#define RX_IRQ(n) BIT(0 + 2 * (n))
+#define RX_IRQ_MASK 0x5555
+#define TX_IRQ(n) BIT(1 + 2 * (n))
+#define TX_IRQ_MASK 0xaaaa
+
+#define FIFO_STAT_REG(n) (0x0100 + 0x4 * (n))
+#define FIFO_STAT_MASK GENMASK(0, 0)
+
+#define MSG_STAT_REG(n) (0x0140 + 0x4 * (n))
+#define MSG_STAT_MASK GENMASK(2, 0)
+
+#define MSG_DATA_REG(n) (0x0180 + 0x4 * (n))
+
+#define mbox_dbg(mbox, ...) dev_dbg((mbox)->controller.dev, __VA_ARGS__)
+
+struct sunxi_msgbox {
+ struct mbox_controller controller;
+ struct clk *clk;
+ spinlock_t lock;
+ void __iomem *regs;
+};
+
+static bool sunxi_msgbox_last_tx_done(struct mbox_chan *chan);
+static bool sunxi_msgbox_peek_data(struct mbox_chan *chan);
+
+static inline int channel_number(struct mbox_chan *chan)
+{
+ return chan - chan->mbox->chans;
+}
+
+static inline struct sunxi_msgbox *channel_to_msgbox(struct mbox_chan *chan)
+{
+ return chan->con_priv;
+}
+
+static irqreturn_t sunxi_msgbox_irq(int irq, void *dev_id)
+{
+ struct sunxi_msgbox *mbox = dev_id;
+ uint32_t status;
+ int n;
+
+ /* Only examine channels that are currently enabled. */
+ status = readl(mbox->regs + LOCAL_IRQ_EN_REG) &
+ readl(mbox->regs + LOCAL_IRQ_STAT_REG);
+
+ if (!(status & RX_IRQ_MASK))
+ return IRQ_NONE;
+
+ for (n = 0; n < NUM_CHANS; ++n) {
+ struct mbox_chan *chan = &mbox->controller.chans[n];
+
+ if (!(status & RX_IRQ(n)))
+ continue;
+
+ while (sunxi_msgbox_peek_data(chan)) {
+ uint32_t msg = readl(mbox->regs + MSG_DATA_REG(n));
+
+ mbox_dbg(mbox, "Channel %d received 0x%08x\n", n, msg);
+ mbox_chan_received_data(chan, &msg);
+ }
+
+ /* The IRQ can be cleared only once the FIFO is empty. */
+ writel(RX_IRQ(n), mbox->regs + LOCAL_IRQ_STAT_REG);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int sunxi_msgbox_send_data(struct mbox_chan *chan, void *data)
+{
+ struct sunxi_msgbox *mbox = channel_to_msgbox(chan);
+ int n = channel_number(chan);
+ uint32_t msg = *(uint32_t *)data;
+
+ /* Using a channel backwards gets the hardware into a bad state. */
+ if (WARN_ON_ONCE(!(readl(mbox->regs + CTRL_REG(n)) & CTRL_TX(n))))
+ return 0;
+
+ /* We cannot post a new message if the FIFO is full. */
+ if (readl(mbox->regs + FIFO_STAT_REG(n)) & FIFO_STAT_MASK) {
+ mbox_dbg(mbox, "Channel %d busy sending 0x%08x\n", n, msg);
+ return -EBUSY;
+ }
+
+ writel(msg, mbox->regs + MSG_DATA_REG(n));
+ mbox_dbg(mbox, "Channel %d sent 0x%08x\n", n, msg);
+
+ return 0;
+}
+
+static int sunxi_msgbox_startup(struct mbox_chan *chan)
+{
+ struct sunxi_msgbox *mbox = channel_to_msgbox(chan);
+ int n = channel_number(chan);
+
+ /* The coprocessor is responsible for setting channel directions. */
+ if (readl(mbox->regs + CTRL_REG(n)) & CTRL_RX(n)) {
+ /* Flush the receive FIFO. */
+ while (sunxi_msgbox_peek_data(chan))
+ readl(mbox->regs + MSG_DATA_REG(n));
+ writel(RX_IRQ(n), mbox->regs + LOCAL_IRQ_STAT_REG);
+
+ /* Enable the receive IRQ. */
+ spin_lock(&mbox->lock);
+ writel(readl(mbox->regs + LOCAL_IRQ_EN_REG) | RX_IRQ(n),
+ mbox->regs + LOCAL_IRQ_EN_REG);
+ spin_unlock(&mbox->lock);
+ }
+
+ mbox_dbg(mbox, "Channel %d startup complete\n", n);
+
+ return 0;
+}
+
+static void sunxi_msgbox_shutdown(struct mbox_chan *chan)
+{
+ struct sunxi_msgbox *mbox = channel_to_msgbox(chan);
+ int n = channel_number(chan);
+
+ if (readl(mbox->regs + CTRL_REG(n)) & CTRL_RX(n)) {
+ /* Disable the receive IRQ. */
+ spin_lock(&mbox->lock);
+ writel(readl(mbox->regs + LOCAL_IRQ_EN_REG) & ~RX_IRQ(n),
+ mbox->regs + LOCAL_IRQ_EN_REG);
+ spin_unlock(&mbox->lock);
+
+ /* Attempt to flush the FIFO until the IRQ is cleared. */
+ do {
+ while (sunxi_msgbox_peek_data(chan))
+ readl(mbox->regs + MSG_DATA_REG(n));
+ writel(RX_IRQ(n), mbox->regs + LOCAL_IRQ_STAT_REG);
+ } while (readl(mbox->regs + LOCAL_IRQ_STAT_REG) & RX_IRQ(n));
+ }
+
+ mbox_dbg(mbox, "Channel %d shutdown complete\n", n);
+}
+
+static bool sunxi_msgbox_last_tx_done(struct mbox_chan *chan)
+{
+ struct sunxi_msgbox *mbox = channel_to_msgbox(chan);
+ int n = channel_number(chan);
+
+ /*
+ * The hardware allows snooping on the remote user's IRQ statuses.
+ * We consider a message to be acknowledged only once the receive IRQ
+ * for that channel is cleared. Since the receive IRQ for a channel
+ * cannot be cleared until the FIFO for that channel is empty, this
+ * ensures that the message has actually been read. It also gives the
+ * recipient an opportunity to perform minimal processing before
+ * acknowledging the message.
+ */
+ return !(readl(mbox->regs + REMOTE_IRQ_STAT_REG) & RX_IRQ(n));
+}
+
+static bool sunxi_msgbox_peek_data(struct mbox_chan *chan)
+{
+ struct sunxi_msgbox *mbox = channel_to_msgbox(chan);
+ int n = channel_number(chan);
+
+ return readl(mbox->regs + MSG_STAT_REG(n)) & MSG_STAT_MASK;
+}
+
+static const struct mbox_chan_ops sunxi_msgbox_chan_ops = {
+ .send_data = sunxi_msgbox_send_data,
+ .startup = sunxi_msgbox_startup,
+ .shutdown = sunxi_msgbox_shutdown,
+ .last_tx_done = sunxi_msgbox_last_tx_done,
+ .peek_data = sunxi_msgbox_peek_data,
+};
+
+static int sunxi_msgbox_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mbox_chan *chans;
+ struct reset_control *reset;
+ struct resource *res;
+ struct sunxi_msgbox *mbox;
+ int i, ret;
+
+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+
+ chans = devm_kcalloc(dev, NUM_CHANS, sizeof(*chans), GFP_KERNEL);
+ if (!chans)
+ return -ENOMEM;
+
+ for (i = 0; i < NUM_CHANS; ++i)
+ chans[i].con_priv = mbox;
+
+ mbox->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(mbox->clk)) {
+ ret = PTR_ERR(mbox->clk);
+ dev_err(dev, "Failed to get clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(mbox->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ reset = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(reset)) {
+ ret = PTR_ERR(reset);
+ dev_err(dev, "Failed to get reset control: %d\n", ret);
+ goto err_disable_unprepare;
+ }
+
+ ret = reset_control_deassert(reset);
+ if (ret) {
+ dev_err(dev, "Failed to deassert reset: %d\n", ret);
+ goto err_disable_unprepare;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto err_disable_unprepare;
+ }
+
+ mbox->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mbox->regs)) {
+ ret = PTR_ERR(mbox->regs);
+ dev_err(dev, "Failed to map MMIO resource: %d\n", ret);
+ goto err_disable_unprepare;
+ }
+
+ /* Disable all IRQs for this end of the msgbox. */
+ writel(0, mbox->regs + LOCAL_IRQ_EN_REG);
+
+ ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
+ sunxi_msgbox_irq, 0, dev_name(dev), mbox);
+ if (ret) {
+ dev_err(dev, "Failed to register IRQ handler: %d\n", ret);
+ goto err_disable_unprepare;
+ }
+
+ mbox->controller.dev = dev;
+ mbox->controller.ops = &sunxi_msgbox_chan_ops;
+ mbox->controller.chans = chans;
+ mbox->controller.num_chans = NUM_CHANS;
+ mbox->controller.txdone_irq = false;
+ mbox->controller.txdone_poll = true;
+ mbox->controller.txpoll_period = 5;
+
+ spin_lock_init(&mbox->lock);
+ platform_set_drvdata(pdev, mbox);
+
+ ret = mbox_controller_register(&mbox->controller);
+ if (ret) {
+ dev_err(dev, "Failed to register controller: %d\n", ret);
+ goto err_disable_unprepare;
+ }
+
+ return 0;
+
+err_disable_unprepare:
+ clk_disable_unprepare(mbox->clk);
+
+ return ret;
+}
+
+static int sunxi_msgbox_remove(struct platform_device *pdev)
+{
+ struct sunxi_msgbox *mbox = platform_get_drvdata(pdev);
+
+ mbox_controller_unregister(&mbox->controller);
+ clk_disable_unprepare(mbox->clk);
+
+ return 0;
+}
+
+static const struct of_device_id sunxi_msgbox_of_match[] = {
+ { .compatible = "allwinner,sun6i-a31-msgbox", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sunxi_msgbox_of_match);
+
+static struct platform_driver sunxi_msgbox_driver = {
+ .driver = {
+ .name = "sunxi-msgbox",
+ .of_match_table = sunxi_msgbox_of_match,
+ },
+ .probe = sunxi_msgbox_probe,
+ .remove = sunxi_msgbox_remove,
+};
+module_platform_driver(sunxi_msgbox_driver);
+
+MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
+MODULE_DESCRIPTION("Allwinner sunxi Message Box");
+MODULE_LICENSE("GPL v2");
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 03/10] dt-bindings: mailbox: Add a sunxi message box binding
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: Rob Herring, devicetree, Samuel Holland, linux-kernel,
linux-sunxi, linux-clk, linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
This mailbox hardware is present in Allwinner sun8i, sun9i, and sun50i
SoCs. Add a device tree binding for it.
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
.../mailbox/allwinner,sunxi-msgbox.yaml | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mailbox/allwinner,sunxi-msgbox.yaml
diff --git a/Documentation/devicetree/bindings/mailbox/allwinner,sunxi-msgbox.yaml b/Documentation/devicetree/bindings/mailbox/allwinner,sunxi-msgbox.yaml
new file mode 100644
index 000000000000..f34a1909ab2e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/allwinner,sunxi-msgbox.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mailbox/allwinner,sunxi-msgbox.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner sunxi Message Box
+
+maintainers:
+ - Samuel Holland <samuel@sholland.org>
+
+description: |
+ The hardware message box on sun6i and newer sunxi SoCs is a two-user mailbox
+ controller containing 8 unidirectional FIFOs. An interrupt is raised for
+ received messages, but software must poll to know when a transmitted message
+ has been acknowledged by the remote user. Each FIFO can hold four 32-bit
+ messages; when a FIFO is full, clients must wait before more transmissions.
+
+ Refer to ./mailbox.txt for generic information about mailbox device-tree
+ bindings.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - allwinner,sun8i-a83t-msgbox
+ - allwinner,sun8i-h3-msgbox
+ - allwinner,sun9i-a80-msgbox
+ - allwinner,sun50i-a64-msgbox
+ - allwinner,sun50i-h6-msgbox
+ - const: allwinner,sun6i-a31-msgbox
+ - items:
+ - const: allwinner,sun6i-a31-msgbox
+
+ reg:
+ items:
+ - description: MMIO register range
+
+ clocks:
+ maxItems: 1
+ description: bus clock
+
+ resets:
+ maxItems: 1
+ description: bus reset
+
+ interrupts:
+ maxItems: 1
+ description: controller interrupt
+
+ '#mbox-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+ - interrupts
+ - '#mbox-cells'
+
+examples:
+ - |
+ #include <dt-bindings/clock/sun8i-h3-ccu.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/reset/sun8i-h3-ccu.h>
+
+ msgbox: mailbox@1c17000 {
+ compatible = "allwinner,sun8i-h3-msgbox",
+ "allwinner,sun6i-a31-msgbox";
+ reg = <0x01c17000 0x1000>;
+ clocks = <&ccu CLK_BUS_MSGBOX>;
+ resets = <&ccu RST_BUS_MSGBOX>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
+ };
+
+...
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 02/10] clk: sunxi-ng: Mark AR100 clocks as critical
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
On sun8i, sun9i, and sun50i SoCs, system suspend/resume support requires
firmware running on the AR100 coprocessor (the "SCP"). Such firmware can
provide additional features, such as thermal monitoring and poweron/off
support for boards without a PMIC.
Since the AR100 may be running critical firmware, even if Linux does not
know about it or directly interact with it (all requests may go through
an intermediary interface such as PSCI), Linux must not turn off its
clock.
At this time, such power management firmware only exists for the A64 and
H5 SoCs. However, it makes sense to take care of all CCU drivers now
for consistency, and to ease the transition in the future once firmware
is ported to the other SoCs.
Leaving the clock running is safe even if no firmware is present, since
the AR100 stays in reset by default. In most cases, the AR100 clock is
kept enabled by Linux anyway, since it is the parent of all APB0 bus
peripherals. This change only prevents Linux from turning off the AR100
clock in the rare case that no peripherals are in use.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c | 2 +-
drivers/clk/sunxi-ng/ccu-sun8i-r.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
index 45a1ed3fe674..adf907020951 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
@@ -45,7 +45,7 @@ static struct ccu_div ar100_clk = {
.hw.init = CLK_HW_INIT_PARENTS("ar100",
ar100_r_apb2_parents,
&ccu_div_ops,
- 0),
+ CLK_IS_CRITICAL),
},
};
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
index 4646fdc61053..feef4f750943 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
@@ -45,7 +45,7 @@ static struct ccu_div ar100_clk = {
.hw.init = CLK_HW_INIT_PARENTS_DATA("ar100",
ar100_parents,
&ccu_div_ops,
- 0),
+ CLK_IS_CRITICAL),
},
};
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v4 01/10] clk: sunxi-ng: Mark msgbox clocks as critical
From: Samuel Holland @ 2019-08-20 3:23 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Jassi Brar, Michael Turquette,
Stephen Boyd, Rob Herring, Mark Rutland, Corentin Labbe,
Vasily Khoruzhick
Cc: devicetree, Samuel Holland, linux-kernel, linux-sunxi, linux-clk,
linux-arm-kernel
In-Reply-To: <20190820032311.6506-1-samuel@sholland.org>
The msgbox clock is critical because the hardware it controls is shared
between Linux and system firmware. The message box may be used by the
EL3 secure monitor's PSCI implementation. On 64-bit sunxi SoCs, this is
provided by ARM TF-A; 32-bit SoCs use a different implementation. The
secure monitor uses the message box to forward requests to power
management firmware running on a separate CPU.
It is not enough for the secure monitor to enable the clock each time
Linux performs a SMC into EL3, as both the firmware and Linux can run
concurrently on separate CPUs. So it is never safe for Linux to turn
this clock off, and it should be marked as critical.
At this time, such power management firmware only exists for the A64 and
H5 SoCs. However, it makes sense to take care of all CCU drivers now
for consistency, and to ease the transition in the future once firmware
is ported to the other SoCs.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 3 ++-
drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 3 ++-
drivers/clk/sunxi-ng/ccu-sun8i-a23.c | 3 ++-
drivers/clk/sunxi-ng/ccu-sun8i-a33.c | 3 ++-
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 3 ++-
drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 3 ++-
drivers/clk/sunxi-ng/ccu-sun9i-a80.c | 3 ++-
7 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
index 49bd7a4c015c..045121b50da3 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
@@ -342,8 +342,9 @@ static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1",
0x064, BIT(12), 0);
static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1",
0x064, BIT(20), 0);
+/* Used for communication between firmware components at runtime */
static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
- 0x064, BIT(21), 0);
+ 0x064, BIT(21), CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
0x064, BIT(22), 0);
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
index aebef4af9861..14f39bc4180f 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
@@ -340,8 +340,9 @@ static SUNXI_CCU_GATE(bus_vp9_clk, "bus-vp9", "psi-ahb1-ahb2",
static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2",
0x70c, BIT(0), 0);
+/* Used for communication between firmware components at runtime */
static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "psi-ahb1-ahb2",
- 0x71c, BIT(0), 0);
+ 0x71c, BIT(0), CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "psi-ahb1-ahb2",
0x72c, BIT(0), 0);
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
index 103aa504f6c8..5a28583f57e2 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
@@ -255,8 +255,9 @@ static SUNXI_CCU_GATE(bus_de_fe_clk, "bus-de-fe", "ahb1",
0x064, BIT(14), 0);
static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1",
0x064, BIT(20), 0);
+/* Used for communication between firmware components at runtime */
static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
- 0x064, BIT(21), 0);
+ 0x064, BIT(21), CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
0x064, BIT(22), 0);
static SUNXI_CCU_GATE(bus_drc_clk, "bus-drc", "ahb1",
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
index 91838cd11037..50cf3726ef30 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
@@ -267,8 +267,9 @@ static SUNXI_CCU_GATE(bus_de_fe_clk, "bus-de-fe", "ahb1",
0x064, BIT(14), 0);
static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1",
0x064, BIT(20), 0);
+/* Used for communication between firmware components at runtime */
static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
- 0x064, BIT(21), 0);
+ 0x064, BIT(21), CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
0x064, BIT(22), 0);
static SUNXI_CCU_GATE(bus_drc_clk, "bus-drc", "ahb1",
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
index 2b434521c5cc..4ab3a76f4ffa 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
@@ -339,8 +339,9 @@ static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1",
0x064, BIT(12), 0);
static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1",
0x064, BIT(20), 0);
+/* Used for communication between firmware components at runtime */
static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
- 0x064, BIT(21), 0);
+ 0x064, BIT(21), CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
0x064, BIT(22), 0);
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
index 6b636362379e..7429d3fe8fb7 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -273,8 +273,9 @@ static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1",
0x064, BIT(12), 0);
static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1",
0x064, BIT(20), 0);
+/* Used for communication between firmware components at runtime */
static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
- 0x064, BIT(21), 0);
+ 0x064, BIT(21), CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
0x064, BIT(22), 0);
diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
index dcac1391767f..47d1d18b6f38 100644
--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
+++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c
@@ -748,8 +748,9 @@ static SUNXI_CCU_GATE(bus_usb_clk, "bus-usb", "ahb1",
0x584, BIT(1), 0);
static SUNXI_CCU_GATE(bus_gmac_clk, "bus-gmac", "ahb1",
0x584, BIT(17), 0);
+/* Used for communication between firmware components at runtime */
static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
- 0x584, BIT(21), 0);
+ 0x584, BIT(21), CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
0x584, BIT(22), 0);
static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1",
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH] ARM: dts: vf610-zii-dev-rev-b: Drop redundant I2C properties
From: Andrey Smirnov @ 2019-08-20 3:19 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Andrey Smirnov, Fabio Estevam, Shawn Guo, linux-kernel,
Chris Healy
Drop redundant I2C properties that are already specified in
vf610-zii-dev.dtsi
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Chris Healy <cphealy@gmail.com>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/arm/boot/dts/vf610-zii-dev-rev-b.dts | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
index 48086c5e8549..e500911ce0a5 100644
--- a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
+++ b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
@@ -323,11 +323,6 @@
};
&i2c0 {
- clock-frequency = <100000>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c0>;
- status = "okay";
-
gpio5: io-expander@20 {
compatible = "nxp,pca9554";
reg = <0x20>;
@@ -350,11 +345,6 @@
};
&i2c2 {
- clock-frequency = <100000>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c2>;
- status = "okay";
-
tca9548@70 {
compatible = "nxp,pca9548";
pinctrl-0 = <&pinctrl_i2c_mux_reset>;
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH] ARM: dts: vf610-zii-scu4-aib: Drop "rs485-rts-delay" property
From: Andrey Smirnov @ 2019-08-20 3:13 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Andrey Smirnov, Fabio Estevam, Shawn Guo, linux-kernel,
Chris Healy
LPUART driver does not support specifying "rs485-rts-delay"
property. Drop it.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Chris Healy <cphealy@gmail.com>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/arm/boot/dts/vf610-zii-scu4-aib.dts | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm/boot/dts/vf610-zii-scu4-aib.dts b/arch/arm/boot/dts/vf610-zii-scu4-aib.dts
index 666ec27a73e3..d8c38ef6a98a 100644
--- a/arch/arm/boot/dts/vf610-zii-scu4-aib.dts
+++ b/arch/arm/boot/dts/vf610-zii-scu4-aib.dts
@@ -685,7 +685,6 @@
linux,rs485-enabled-at-boot-time;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
- rs485-rts-delay = <0 200>;
status = "okay";
};
@@ -693,7 +692,6 @@
linux,rs485-enabled-at-boot-time;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2>;
- rs485-rts-delay = <0 200>;
status = "okay";
};
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH] ARM: dts: vf610-zii-cfu1: Slow I2C0 down to 100kHz
From: Andrey Smirnov @ 2019-08-20 3:08 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Andrey Smirnov, Fabio Estevam, Shawn Guo, linux-kernel,
Chris Healy
Fiber-optic module attached to the bus is only rated to work at
100kHz, so drop the bus frequncy to accomodate that.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Chris Healy <cphealy@gmail.com>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/arm/boot/dts/vf610-zii-cfu1.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/vf610-zii-cfu1.dts b/arch/arm/boot/dts/vf610-zii-cfu1.dts
index ff460a1de85a..28732249cfc0 100644
--- a/arch/arm/boot/dts/vf610-zii-cfu1.dts
+++ b/arch/arm/boot/dts/vf610-zii-cfu1.dts
@@ -207,7 +207,7 @@
};
&i2c0 {
- clock-frequency = <400000>;
+ clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0>;
status = "okay";
--
2.21.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v2 0/9] Exynos Adaptive Supply Voltage support
From: Viresh Kumar @ 2019-08-20 3:01 UTC (permalink / raw)
To: Sylwester Nawrocki
Cc: devicetree, linux-samsung-soc, linux-pm, vireshk, b.zolnierkie,
linux-kernel, krzk, robh+dt, kgene, pankaj.dubey,
linux-arm-kernel, Marek Szyprowski
In-Reply-To: <b7093aaf-ea56-c390-781f-6f9d0780bd8e@samsung.com>
On 19-08-19, 15:39, Sylwester Nawrocki wrote:
> Unfortunately not, the patch set as I see it is another way of updating
> an OPP after it was parsed from DT. OPP remove/add could work equally
> well in our use case.
Adding OPPs dynamically has limitations, you can't set many values which are
otherwise possible with DT. And removing/adding is not the right thing to do
technically.
> The problem is that we have the information on how to translate the
> common OPP voltage to a voltage specific to given silicon encoded jointly
> in the ASV tables and the CHIPID registers (efuse/OTP memory).
> Additionally, algorithm of selecting ASV data (OPP voltage) based on
> the "key" data from registers is not generic, it is usually different
> per each SoC type.
>
> I tried to identify some patterns in those tables in order to simplify
> possible DT binding, but that was not really successful. I ended up just
> keeping whole tables.
Sorry but I am unable to understand the difficulty you are facing now. So what I
suggest is something like this.
- Use DT to get a frequency and voltage for each frequency.
- At runtime, based on SoC, registers, efuses, etc, update the voltage of the
OPPs.
- This algo can be different for each SoC, no one is stopping you from doing
that.
Am I missing something ?
--
viresh
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 1/1] arm64: dts: rockchip: Add support for TB-96AI board
From: Elon Zhang @ 2019-08-20 2:35 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: mark.rutland, devicetree, heiko, linux-kernel, linux-rockchip,
robh+dt, linux-arm-kernel
In-Reply-To: <20190805112810.GA19736@mani>
Hi Mani,
Thanks for your review. Please see comments inline.
在 8/5/2019 19:28, Manivannan Sadhasivam 写道:
> Hi Elon,
>
> Thanks for the v2. Still the DT needs to be cleaned up a bit. I have tested this
> patch on TB96-AI SOM/Carrier board and found that the USB ports are not working
> at all! Do we need to change any switch settings?
Yes. The USB ports can not work. I have already added all USB related
setting. I tried
rockchip internel rk3399.dtsi and the USB ports can work, so I think the
cause is SoC related
setting difference in mainline kernel.
I can not figure it out for now, should I remove the usb related node in
this patch?
>
> Comments are inline.
>
> On Mon, Aug 05, 2019 at 09:57:55AM +0800, Elon Zhang wrote:
>> Add devicetree support for RK3399Pro TB-96AI board, one of
>> the 96Boards family.
>>
>> The TB-96AI board is a 96Boards Compute SOM design, launched
>> by Linaro, Rockchip and Beiqicloud.
>>
>> More information can be obtained from the following websites:
>> 1.https://www.96boards.org/product/tb-96ai/
>> 2.http://t.rock-chips.com/
>> 3.http://www.beiqicloud.com/
>>
>> This patch add basic node for the board and support booting up
>> to Fedora.
>>
>> Signed-off-by: Elon Zhang <zhangzj@rock-chips.com>
>> ---
>> changes since v1:
>> - remove needless node
>> - using a standard LED formats for 96Boards
>>
>> arch/arm64/boot/dts/rockchip/Makefile | 1 +
>> .../boot/dts/rockchip/rk3399pro-tb-96ai.dts | 560 ++++++++++++++++++
>> 2 files changed, 561 insertions(+)
>> create mode 100644 arch/arm64/boot/dts/rockchip/rk3399pro-tb-96ai.dts
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
>> index 5f2687acbf94..3d6c8d4363b5 100644
>> --- a/arch/arm64/boot/dts/rockchip/Makefile
>> +++ b/arch/arm64/boot/dts/rockchip/Makefile
>> @@ -27,3 +27,4 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rock960.dtb
>> dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rockpro64.dtb
>> dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire.dtb
>> dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire-excavator.dtb
>> +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399pro-tb-96ai.dtb
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-tb-96ai.dts b/arch/arm64/boot/dts/rockchip/rk3399pro-tb-96ai.dts
>> new file mode 100644
>> index 000000000000..767b37b854ba
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399pro-tb-96ai.dts
>> @@ -0,0 +1,560 @@
>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +/*
>> + * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd.
>> + */
>> +
>> +/dts-v1/;
>> +#include "rk3399pro.dtsi"
>> +#include "rk3399-opp.dtsi"
>> +
>> +/ {
>> + compatible = "beiqi,rk3399pro-tb-96ai", "rockchip,rk3399pro";
>> +
>> + chosen {
>> + stdout-path = "serial2:1500000n8";
>> + };
>> +
>> + xin32k: xin32k {
>> + compatible = "fixed-clock";
>> + clock-frequency = <32768>;
>> + clock-output-names = "xin32k";
>> + #clock-cells = <0>;
>> + };
>> +
>> + vcc5v0_sys: vccsys {
>> + compatible = "regulator-fixed";
>> + regulator-name = "vcc5v0_sys";
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <5000000>;
>> + regulator-max-microvolt = <5000000>;
>> + };
>> +
>> + leds {
> Still the LEDs are not defined as per the format I shared before...
I am not very sure what the format exactly is. Is the LEDs format below
right?
49 leds {
50 compatible = "gpio-leds";
51 pinctrl-names = "default";
52 pinctrl-0 = <&user_led1>,<&user_led2>,<&user_led3>;
53
54 user_led1 {
55 label = "green:user1";
56 gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
57 retain-state-suspended;
58 };
59
60 user_led2 {
61 label = "green:user2";
62 gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>;
63 retain-state-suspended;
64 };
65
66 user_led3 {
67 label = "green:user3";
68 gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
69 retain-state-suspended;
70 };
71 };
>
>> + compatible = "gpio-leds";
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&work_led1>,<&work_led2>,<&work_led3>;
>> +
>> + work_led1 {
>> + gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
>> + label = "system_work_led1";
>> + retain-state-suspended;
>> + };
>> +
>> + work_led2 {
>> + gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>;
>> + label = "system_work_led2";
>> + retain-state-suspended;
>> + };
>> +
>> + work_led3 {
>> + gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
>> + label = "system_work_led3";
>> + retain-state-suspended;
>> + };
>> + };
>> +};
>> +
>> +&cpu_l0 {
>> + cpu-supply = <&vdd_cpu_l>;
>> +};
>> +
>> +&cpu_l1 {
>> + cpu-supply = <&vdd_cpu_l>;
>> +};
>> +
>> +&cpu_l2 {
>> + cpu-supply = <&vdd_cpu_l>;
>> +};
>> +
>> +&cpu_l3 {
>> + cpu-supply = <&vdd_cpu_l>;
>> +};
>> +
>> +&cpu_b0 {
>> + cpu-supply = <&vdd_cpu_b>;
>> +};
>> +
>> +&cpu_b1 {
>> + cpu-supply = <&vdd_cpu_b>;
>> +};
>> +
>> +&emmc_phy {
>> + status = "okay";
>> +};
>> +
>> +&i2c0 {
>> + status = "okay";
>> + i2c-scl-rising-time-ns = <180>;
>> + i2c-scl-falling-time-ns = <30>;
>> + clock-frequency = <400000>;
>> +
>> + rk809: pmic@20 {
>> + compatible = "rockchip,rk809";
>> + reg = <0x20>;
>> + interrupt-parent = <&gpio1>;
>> + interrupts = <RK_PC2 IRQ_TYPE_LEVEL_LOW>;
>> + pinctrl-names = "default", "pmic-sleep",
>> + "pmic-power-off", "pmic-reset";
> Does these pinctrl configs useful other than default?
These pinctrl configs are used for sleep/wake. Since mainline MFD and
pinctrl driver
has no pinctrl support for RK809, these pinctrl configs will be removed
other than default.
>
>> + pinctrl-0 = <&pmic_int_l>;
>> + pinctrl-1 = <&soc_slppin_slp>, <&rk809_slppin_slp>;
>> + pinctrl-2 = <&soc_slppin_gpio>, <&rk809_slppin_pwrdn>;
>> + pinctrl-3 = <&soc_slppin_gpio>,<&rk809_slppin_null>;
>> + rockchip,system-power-controller;
>> + pmic-reset-func = <1>;
>> + wakeup-source;
>> + #clock-cells = <1>;
>> + clock-output-names = "rk808-clkout1", "rk808-clkout2";
>> +
>> + vcc1-supply = <&vcc5v0_sys>;
>> + vcc2-supply = <&vcc5v0_sys>;
>> + vcc3-supply = <&vcc5v0_sys>;
>> + vcc4-supply = <&vcc5v0_sys>;
>> + vcc5-supply = <&vcc_buck5>;
>> + vcc6-supply = <&vcc_buck5>;
>> + vcc7-supply = <&vcc3v3_sys>;
>> + vcc8-supply = <&vcc3v3_sys>;
>> + vcc9-supply = <&vcc5v0_sys>;
>> +
>> + pwrkey {
>> + status = "okay";
> No compatible needed?
No compatible needed. It is RK809 internel implement.
>
>> + };
>> +
>> + rtc {
>> + status = "okay";
> No compatible needed?
ditto.
>
>> + };
>> +
>> + pinctrl_rk8xx: pinctrl_rk8xx {
> Mainline MFD driver has no pinctrl support for RK809.
Yes. This node will be removed.
Thank,
Elon
>
>> + gpio-controller;
>> + #gpio-cells = <2>;
>> +
>> + rk809_slppin_null: rk809_slppin_null {
>> + pins = "gpio_slp";
>> + function = "pin_fun0";
>> + };
>> +
>> + rk809_slppin_slp: rk809_slppin_slp {
>> + pins = "gpio_slp";
>> + function = "pin_fun1";
>> + };
>> +
>> + rk809_slppin_pwrdn: rk809_slppin_pwrdn {
>> + pins = "gpio_slp";
>> + function = "pin_fun2";
>> + };
>> +
>> + rk809_slppin_rst: rk809_slppin_rst {
>> + pins = "gpio_slp";
>> + function = "pin_fun3";
>> + };
>> + };
>> +
>> + regulators {
>> + vdd_center: DCDC_REG1 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <750000>;
>> + regulator-max-microvolt = <1350000>;
>> + regulator-initial-mode = <0x2>;
>> + regulator-name = "vdd_center";
> Please match the regulator names with schematic.
>
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <900000>;
>> + };
>> + };
>> +
>> + vdd_cpu_l: DCDC_REG2 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <750000>;
>> + regulator-max-microvolt = <1350000>;
>> + regulator-ramp-delay = <6001>;
>> + regulator-initial-mode = <0x2>;
>> + regulator-name = "vdd_cpu_l";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc_ddr: DCDC_REG3 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-name = "vcc_ddr";
>> + regulator-initial-mode = <0x2>;
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + };
>> + };
>> +
>> + vcc3v3_sys: DCDC_REG4 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <3300000>;
>> + regulator-max-microvolt = <3300000>;
>> + regulator-initial-mode = <0x2>;
>> + regulator-name = "vcc3v3_sys";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <3300000>;
>> + };
>> + };
>> +
>> + vcc_buck5: DCDC_REG5 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <2200000>;
>> + regulator-max-microvolt = <2200000>;
>> + regulator-name = "vcc_buck5";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <2200000>;
>> + };
>> + };
>> +
>> + vcca_0v9: LDO_REG1 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <900000>;
>> + regulator-max-microvolt = <900000>;
>> + regulator-name = "vcca_0v9";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc_1v8: LDO_REG2 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> +
>> + regulator-name = "vcc_1v8";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <1800000>;
>> + };
>> + };
>> +
>> + vcc0v9_soc: LDO_REG3 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <900000>;
>> + regulator-max-microvolt = <900000>;
>> +
>> + regulator-name = "vcc0v9_soc";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <900000>;
>> + };
>> + };
>> +
>> + vcca_1v8: LDO_REG4 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> +
>> + regulator-name = "vcca_1v8";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vdd1v5_dvp: LDO_REG5 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1500000>;
>> + regulator-max-microvolt = <1500000>;
>> +
>> + regulator-name = "vdd1v5_dvp";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc_1v5: LDO_REG6 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1500000>;
>> + regulator-max-microvolt = <1500000>;
>> +
>> + regulator-name = "vcc_1v5";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc_3v0: LDO_REG7 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <3000000>;
>> + regulator-max-microvolt = <3000000>;
>> +
>> + regulator-name = "vcc_3v0";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vccio_sd: LDO_REG8 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <3300000>;
>> +
>> + regulator-name = "vccio_sd";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <3300000>;
>> + };
>> + };
>> +
>> + vcc_sd: LDO_REG9 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <3300000>;
>> + regulator-max-microvolt = <3300000>;
>> +
>> + regulator-name = "vcc_sd";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <3300000>;
>> + };
>> + };
>> +
>> + vcc5v0_usb: SWITCH_REG1 {
>> + regulator-min-microvolt = <5000000>;
>> + regulator-max-microvolt = <5000000>;
>> +
>> + regulator-name = "vcc5v0_usb";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vccio_3v3: SWITCH_REG2 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <3300000>;
>> + regulator-max-microvolt = <3300000>;
>> +
>> + regulator-name = "vccio_3v3";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> + };
>> + };
>> +
>> + vdd_cpu_b: regulator@1c {
>> + compatible = "fcs,fan53555";
>> + reg = <0x1c>;
>> + vin-supply = <&vcc5v0_sys>;
>> + pinctrl-0 = <&vsel1_gpio>;
>> + vsel-gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>;
>> + regulator-name = "vdd_cpu_b";
>> + regulator-min-microvolt = <712500>;
>> + regulator-max-microvolt = <1500000>;
>> + regulator-ramp-delay = <2300>;
>> + fcs,suspend-voltage-selector = <1>;
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-initial-state = <3>;
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vdd_gpu: regulator@10 {
>> + compatible = "fcs,fan53555";
>> + status = "okay";
>> + reg = <0x10>;
>> + vin-supply = <&vcc5v0_sys>;
>> + pinctrl-0 = <&vsel2_gpio>;
>> + vsel-gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>;
>> + regulator-name = "vdd_gpu";
>> + regulator-min-microvolt = <735000>;
>> + regulator-max-microvolt = <1400000>;
>> + regulator-ramp-delay = <2300>;
>> + fcs,suspend-voltage-selector = <1>;
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +};
>> +
>> +&i2c8 {
>> + status = "okay";
>> + i2c-scl-rising-time-ns = <345>;
>> + i2c-scl-falling-time-ns = <11>;
>> + clock-frequency = <100000>;
>> +};
>> +
>> +&io_domains {
>> + status = "okay";
>> + bt656-supply = <&vcca_1v8>; /* APIO2_VDD */
>> + audio-supply = <&vcca_1v8>; /* APIO5_VDD */
>> + sdmmc-supply = <&vccio_sd>; /* SDMMC0_VDD */
>> + gpio1830-supply = <&vcc_1v8>; /* APIO4_VDD */
>> +};
>> +
>> +&pinctrl {
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&npu_ref_clk>;
>> +
>> + leds {
>> + work_led1: work_led1 {
>> + rockchip,pins =
>> + <2 5 RK_FUNC_GPIO &pcfg_pull_none>;
>> + };
>> +
>> + work_led2: work_led2 {
>> + rockchip,pins =
>> + <2 4 RK_FUNC_GPIO &pcfg_pull_none>;
>> + };
>> +
>> + work_led3: work_led3 {
>> + rockchip,pins =
>> + <2 3 RK_FUNC_GPIO &pcfg_pull_none>;
>> + };
>> + };
>> +
>> + npu_clk {
>> + npu_ref_clk: npu-ref-clk {
>> + rockchip,pins =
>> + <0 RK_PA2 1 &pcfg_pull_none>;
>> + };
>> + };
>> +
>> + pmic {
>> + pmic_int_l: pmic-int-l {
>> + rockchip,pins =
>> + <1 RK_PC2 0 &pcfg_pull_up>;
>> + };
>> +
>> + soc_slppin_gpio: soc-slppin-gpio {
>> + rockchip,pins =
>> + <1 RK_PA5 0 &pcfg_output_low>;
>> + };
>> +
>> + soc_slppin_slp: soc-slppin-slp {
>> + rockchip,pins =
>> + <1 RK_PA5 1 &pcfg_pull_down>;
>> + };
>> +
>> + vsel1_gpio: vsel1-gpio {
>> + rockchip,pins =
>> + <1 RK_PC1 0 &pcfg_pull_down>;
>> + };
>> +
>> + vsel2_gpio: vsel2-gpio {
>> + rockchip,pins =
>> + <1 RK_PB6 0 &pcfg_pull_down>;
>> + };
>> + };
>> +
>> + usb3 {
>> + usb3_host_en: usb3-host-en {
>> + rockchip,pins =
>> + <2 RK_PA2 RK_FUNC_GPIO &pcfg_output_high>;
>> + };
>> + };
>> +};
>> +
>> +&pmu_io_domains {
>> + status = "okay";
>> + pmu1830-supply = <&vcc_1v8>;
>> +};
>> +
>> +&pwm0 {
>> + status = "okay";
>> +};
>> +
>> +&pwm2 {
>> + status = "okay";
>> +};
>> +
>> +&saradc {
>> + status = "okay";
>> + vref-supply = <&vcc_1v8>;
>> +};
>> +
>> +&sdhci {
>> + bus-width = <8>;
>> + mmc-hs400-1_8v;
>> + non-removable;
>> + keep-power-in-suspend;
>> + mmc-hs400-enhanced-strobe;
>> + status = "okay";
>> +};
>> +
>> +&tcphy1 {
> No tcphy0? I can see this used in schematics.
>
>> + status = "okay";
>> +};
>> +
>> +&tsadc {
>> + rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */
>> + rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */
>> + status = "okay";
>> +};
>> +
>> +&u2phy1 {
> No u2phy0?
>
>> + status = "okay";
>> +
>> + u2phy1_otg: otg-port {
>> + status = "okay";
>> + };
>> +
>> + u2phy1_host: host-port {
>> + phy-supply = <&vcc5v0_usb>;
>> + status = "okay";
>> + };
>> +};
>> +
>> +&uart0 {
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&uart0_xfer &uart0_cts>;
>> + status = "okay";
>> +};
>> +
>> +&uart2 {
>> + status = "okay";
>> +};
>> +
>> +&uart4 {
>> + status = "okay";
>> +};
>> +
>> +&usb_host0_ehci {
>> + status = "okay";
>> +};
>> +
>> +&usb_host1_ehci {
>> + status = "okay";
>> +};
>> +
>> +&usb_host0_ohci {
>> + status = "okay";
>> +};
>> +
>> +&usb_host1_ohci {
>> + status = "okay";
>> +};
>> +
>> +&usbdrd3_1 {
>> + status = "okay";
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&usb3_host_en>;
>> +};
>> +
>> +&usbdrd_dwc3_0 {
> No usbdrd3_0?
>
> Thanks,
> Mani
>
>> + status = "okay";
>> +};
>> +
>> +&usbdrd_dwc3_1 {
>> + snps,dis-u3-autosuspend-quirk;
>> + status = "okay";
>> +};
>> +
>> --
>> 2.17.1
>>
>>
>>
>
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] clk: imx: pll14xx: avoid glitch when set rate
From: Peng Fan @ 2019-08-20 2:17 UTC (permalink / raw)
To: mturquette@baylibre.com, sboyd@kernel.org, shawnguo@kernel.org,
s.hauer@pengutronix.de, festevam@gmail.com
Cc: Peng Fan, Abel Vesa, Anson Huang, linux-kernel@vger.kernel.org,
dl-linux-imx, kernel@pengutronix.de, linux-clk@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, Jacky Bai
From: Peng Fan <peng.fan@nxp.com>
According to PLL1443XA and PLL1416X spec,
"When BYPASS is 0 and RESETB is changed from 0 to 1, FOUT starts to
output unstable clock until lock time passes. PLL1416X/PLL1443XA may
generate a glitch at FOUT."
So set BYPASS when RESETB is changed from 0 to 1 to avoid glitch.
In the end of set rate, BYPASS will be cleared.
Fixes: 8646d4dcc7fb ("clk: imx: Add PLLs driver for imx8mm soc")
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/imx/clk-pll14xx.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index b7213023b238..bd072556bc44 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -191,6 +191,10 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
tmp &= ~RST_MASK;
writel_relaxed(tmp, pll->base);
+ /* Enable BYPASS */
+ tmp |= BYPASS_MASK;
+ writel(tmp, pll->base);
+
div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
(rate->sdiv << SDIV_SHIFT);
writel_relaxed(div_val, pll->base + 0x4);
@@ -250,6 +254,10 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
tmp &= ~RST_MASK;
writel_relaxed(tmp, pll->base);
+ /* Enable BYPASS */
+ tmp |= BYPASS_MASK;
+ writel_relaxed(tmp, pll->base);
+
div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
(rate->sdiv << SDIV_SHIFT);
writel_relaxed(div_val, pll->base + 0x4);
--
2.16.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 4/4] arm64: implement KPROBES_ON_FTRACE
From: Jisheng Zhang @ 2019-08-20 2:16 UTC (permalink / raw)
To: Naveen N. Rao
Cc: Catalin Marinas, x86@kernel.org, linux-kernel@vger.kernel.org,
Anil S Keshavamurthy, Ingo Molnar, Borislav Petkov,
Masami Hiramatsu, H. Peter Anvin, Steven Rostedt, Thomas Gleixner,
Will Deacon, David S. Miller,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <1566232996.v8nlwmnjqa.naveen@linux.ibm.com>
On Mon, 19 Aug 2019 22:22:12 +0530 "Naveen N. Rao" wrote:
>
>
> Jisheng Zhang wrote:
> > This patch implements KPROBES_ON_FTRACE for arm64.
> >
> > ~ # mount -t debugfs debugfs /sys/kernel/debug/
> > ~ # cd /sys/kernel/debug/
> > /sys/kernel/debug # echo 'p _do_fork' > tracing/kprobe_events
> >
> > before the patch:
> >
> > /sys/kernel/debug # cat kprobes/list
> > ffffff801009ff7c k _do_fork+0x4 [DISABLED]
>
> This looks wrong -- we should not be allowing kprobe to be registered on
Yes. I made a mistake when dumping this log. The kernel isn't as clean
as "before the patch".
> ftrace address without KPROBES_ON_FTRACE. Is _do_fork+0x4 the location
> of ftrace entry on arm64?
Indeed, w/o KPROBES_ON_FTRACE, it should be _do_fork+0x0
Thanks
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
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