* [PATCH 01/18] include: provide linux/errno.h
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 02/18] include: add linux/refcount.h Ahmad Fatoum
` (16 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We don't have the historic baggage of having to support different errno
definitions depending on architecture. We thus have only
asm-generic/errno.h and include that from errno.h and elsewhere
directly.
Kernel code however includes <linux/errno.h>, so let's provide that file
as well and define there the Linux-specific errno's and include
<asm-generic/errno.h> for all other errnos.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/powerpc/lib/misc.S | 2 +-
arch/powerpc/lib/ppcstring.S | 2 +-
common/optee.c | 2 +-
include/asm-generic/errno.h | 11 ----------
include/bbu.h | 2 +-
include/errno.h | 2 +-
include/linux/err.h | 2 +-
include/linux/errno.h | 36 +++++++++++++++++++++++++++++++++
include/linux/pstore.h | 2 +-
include/mach/at91/iomux.h | 2 +-
include/tee/optee.h | 2 +-
lib/reed_solomon/reed_solomon.c | 2 +-
12 files changed, 46 insertions(+), 21 deletions(-)
create mode 100644 include/linux/errno.h
diff --git a/arch/powerpc/lib/misc.S b/arch/powerpc/lib/misc.S
index c45f02ba3af0..024d26ed58e9 100644
--- a/arch/powerpc/lib/misc.S
+++ b/arch/powerpc/lib/misc.S
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <asm/ppc_asm.tmpl>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
.globl __ashrdi3
__ashrdi3:
diff --git a/arch/powerpc/lib/ppcstring.S b/arch/powerpc/lib/ppcstring.S
index cce85e3252a8..55f96cc9a448 100644
--- a/arch/powerpc/lib/ppcstring.S
+++ b/arch/powerpc/lib/ppcstring.S
@@ -9,7 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <asm/ppc_asm.tmpl>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
.globl strcpy
strcpy:
diff --git a/common/optee.c b/common/optee.c
index b460fbcd0161..32a6c0a15b94 100644
--- a/common/optee.c
+++ b/common/optee.c
@@ -4,7 +4,7 @@
#include <tee/optee.h>
#include <linux/printk.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
int optee_verify_header(struct optee_header *hdr)
{
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
index a96f8864dfd4..7629d5c8dd58 100644
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -134,15 +134,4 @@
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED 129 /* Key was rejected by service */
-/* Should never be seen by user programs */
-#define ERESTARTSYS 512
-#define ERESTARTNOINTR 513
-#define ERESTARTNOHAND 514 /* restart if no handler.. */
-#define ENOIOCTLCMD 515 /* No ioctl command */
-#define EPROBE_DEFER 517 /* Driver requests probe retry */
-
-#define ENOTSUPP 524 /* Operation is not supported */
-
-#define _LAST_ERRNO 524
-
#endif
diff --git a/include/bbu.h b/include/bbu.h
index cec7e22d4d90..0a4f324ade5b 100644
--- a/include/bbu.h
+++ b/include/bbu.h
@@ -2,7 +2,7 @@
#ifndef __INCLUDE_BBU_H
#define __INCLUDE_BBU_H
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#include <linux/list.h>
#include <linux/types.h>
#include <filetype.h>
diff --git a/include/errno.h b/include/errno.h
index 164426596604..6ec7af4d7e9f 100644
--- a/include/errno.h
+++ b/include/errno.h
@@ -2,7 +2,7 @@
#ifndef __ERRNO_H
#define __ERRNO_H
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#include <linux/err.h>
extern int errno;
diff --git a/include/linux/err.h b/include/linux/err.h
index db7ad6cc5bfa..d743b4d0928a 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -5,7 +5,7 @@
#include <linux/compiler.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
/*
* Kernel pointers have redundant information, so we can use a
diff --git a/include/linux/errno.h b/include/linux/errno.h
new file mode 100644
index 000000000000..b3bf44d24936
--- /dev/null
+++ b/include/linux/errno.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_ERRNO_H
+#define _LINUX_ERRNO_H
+
+#include <asm-generic/errno.h>
+
+
+/*
+ * These should never be seen by user programs. To return one of ERESTART*
+ * codes, signal_pending() MUST be set. Note that ptrace can observe these
+ * at syscall exit tracing, but they will never be left for the debugged user
+ * process to see.
+ */
+#define ERESTARTSYS 512
+#define ERESTARTNOINTR 513
+#define ERESTARTNOHAND 514 /* restart if no handler.. */
+#define ENOIOCTLCMD 515 /* No ioctl command */
+#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
+#define EPROBE_DEFER 517 /* Driver requests probe retry */
+#define EOPENSTALE 518 /* open found a stale dentry */
+#define ENOPARAM 519 /* Parameter not supported */
+
+/* Defined for the NFSv3 protocol */
+#define EBADHANDLE 521 /* Illegal NFS file handle */
+#define ENOTSYNC 522 /* Update synchronization mismatch */
+#define EBADCOOKIE 523 /* Cookie is stale */
+#define ENOTSUPP 524 /* Operation is not supported */
+#define ETOOSMALL 525 /* Buffer or request is too small */
+#define ESERVERFAULT 526 /* An untranslatable error occurred */
+#define EBADTYPE 527 /* Type not supported by server */
+#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */
+#define EIOCBQUEUED 529 /* iocb queued, will get completion event */
+#define ERECALLCONFLICT 530 /* conflict with recalled state */
+#define ENOGRACE 531 /* NFS file lock reclaim refused */
+
+#endif
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index f598f31a5438..90e3bd2d4255 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -23,7 +23,7 @@
#include <linux/time.h>
#include <linux/types.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
struct module;
diff --git a/include/mach/at91/iomux.h b/include/mach/at91/iomux.h
index 84b50e05e0dc..f3ac93474222 100644
--- a/include/mach/at91/iomux.h
+++ b/include/mach/at91/iomux.h
@@ -7,7 +7,7 @@
#define __ASM_ARCH_AT91_GPIO_H
#include <io.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#include <mach/at91/at91_pio.h>
#include <mach/at91/hardware.h>
#include <mach/at91/gpio.h>
diff --git a/include/tee/optee.h b/include/tee/optee.h
index fa124236ba5e..607f5072d385 100644
--- a/include/tee/optee.h
+++ b/include/tee/optee.h
@@ -11,7 +11,7 @@
#define _OPTEE_H
#include <types.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#define OPTEE_MAGIC 0x4554504f
#define OPTEE_VERSION 1
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
index 51c67c3c8d5d..80c0ec4f7ab9 100644
--- a/lib/reed_solomon/reed_solomon.c
+++ b/lib/reed_solomon/reed_solomon.c
@@ -44,7 +44,7 @@
#include <module.h>
#include <linux/string.h>
#include <stdio.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
/* This list holds all currently allocated rs control structures */
static LIST_HEAD (rslist);
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 02/18] include: add linux/refcount.h
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 01/18] include: provide linux/errno.h Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 03/18] bitops: split off linux/bits.h Ahmad Fatoum
` (15 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
For complex interactions, especially in communication protocols, it can
be beneficial to keep the reference counts used in the Linux drivers as
is to avoid resource leaks or use-after-frees.
Provide a simplified kref and refcount API to facilitate this.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/asm-generic/cmpxchg-local.h | 64 +++++++
include/asm-generic/cmpxchg.h | 26 +++
include/linux/atomic.h | 63 +++++++
include/linux/kref.h | 90 +++++++++
include/linux/refcount.h | 271 ++++++++++++++++++++++++++++
lib/Makefile | 1 +
lib/refcount.c | 34 ++++
7 files changed, 549 insertions(+)
create mode 100644 include/asm-generic/cmpxchg-local.h
create mode 100644 include/asm-generic/cmpxchg.h
create mode 100644 include/linux/kref.h
create mode 100644 include/linux/refcount.h
create mode 100644 lib/refcount.c
diff --git a/include/asm-generic/cmpxchg-local.h b/include/asm-generic/cmpxchg-local.h
new file mode 100644
index 000000000000..d93b103d5ca2
--- /dev/null
+++ b/include/asm-generic/cmpxchg-local.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_GENERIC_CMPXCHG_LOCAL_H
+#define __ASM_GENERIC_CMPXCHG_LOCAL_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+extern unsigned long wrong_size_cmpxchg(volatile void *ptr)
+ __noreturn;
+
+/*
+ * Generic version of __cmpxchg_local (disables interrupts). Takes an unsigned
+ * long parameter, supporting various types of architectures.
+ */
+static inline unsigned long __generic_cmpxchg_local(volatile void *ptr,
+ unsigned long old, unsigned long new, int size)
+{
+ unsigned long prev;
+
+ /*
+ * Sanity checking, compile-time.
+ */
+ if (size == 8 && sizeof(unsigned long) != 8)
+ wrong_size_cmpxchg(ptr);
+
+ switch (size) {
+ case 1: prev = *(u8 *)ptr;
+ if (prev == old)
+ *(u8 *)ptr = (u8)new;
+ break;
+ case 2: prev = *(u16 *)ptr;
+ if (prev == old)
+ *(u16 *)ptr = (u16)new;
+ break;
+ case 4: prev = *(u32 *)ptr;
+ if (prev == old)
+ *(u32 *)ptr = (u32)new;
+ break;
+ case 8: prev = *(u64 *)ptr;
+ if (prev == old)
+ *(u64 *)ptr = (u64)new;
+ break;
+ default:
+ wrong_size_cmpxchg(ptr);
+ }
+ return prev;
+}
+
+/*
+ * Generic version of __cmpxchg64_local. Takes an u64 parameter.
+ */
+static inline u64 __generic_cmpxchg64_local(volatile void *ptr,
+ u64 old, u64 new)
+{
+ u64 prev;
+
+ prev = *(u64 *)ptr;
+ if (prev == old)
+ *(u64 *)ptr = new;
+
+ return prev;
+}
+
+#endif
diff --git a/include/asm-generic/cmpxchg.h b/include/asm-generic/cmpxchg.h
new file mode 100644
index 000000000000..b90524135efe
--- /dev/null
+++ b/include/asm-generic/cmpxchg.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Generic non-atomic cmpxchg for porting kernel code.
+ */
+
+#ifndef __ASM_GENERIC_CMPXCHG_H
+#define __ASM_GENERIC_CMPXCHG_H
+
+#ifdef CONFIG_SMP
+#error "Cannot use generic cmpxchg on SMP"
+#endif
+
+#include <asm-generic/cmpxchg-local.h>
+
+#define generic_cmpxchg_local(ptr, o, n) ({ \
+ ((__typeof__(*(ptr)))__generic_cmpxchg_local((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr)))); \
+})
+
+#define generic_cmpxchg64_local(ptr, o, n) \
+ __generic_cmpxchg64_local((ptr), (o), (n))
+
+#define cmpxchg generic_cmpxchg_local
+#define cmpxchg64 generic_cmpxchg64_local
+
+#endif
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
index 9304ab4a34ba..c7bdf5857ce8 100644
--- a/include/linux/atomic.h
+++ b/include/linux/atomic.h
@@ -3,5 +3,68 @@
#define LINUX_ATOMIC_H_
#include <asm-generic/atomic.h>
+#include <linux/compiler.h>
+#include <asm-generic/cmpxchg.h>
+
+#define raw_cmpxchg_relaxed cmpxchg
+
+/**
+ * raw_atomic_cmpxchg_relaxed() - atomic compare and exchange with relaxed ordering
+ * @v: pointer to atomic_t
+ * @old: int value to compare with
+ * @new: int value to assign
+ *
+ * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ *
+ * Safe to use in noinstr code; prefer atomic_cmpxchg_relaxed() elsewhere.
+ *
+ * Return: The original value of @v.
+ */
+static __always_inline int
+raw_atomic_cmpxchg_relaxed(atomic_t *v, int old, int new)
+{
+ return raw_cmpxchg_relaxed(&v->counter, old, new);
+}
+
+/**
+ * atomic_try_cmpxchg_relaxed() - atomic compare and exchange with relaxed ordering
+ * @v: pointer to atomic_t
+ * @old: pointer to int value to compare with
+ * @new: int value to assign
+ *
+ * If (@v == @old), atomically updates @v to @new with relaxed ordering.
+ * Otherwise, updates @old to the current value of @v.
+ *
+ * Return: @true if the exchange occured, @false otherwise.
+ */
+static __always_inline bool
+atomic_try_cmpxchg_relaxed(atomic_t *v, int *old, int new)
+{
+ int r, o = *old;
+ r = raw_atomic_cmpxchg_relaxed(v, o, new);
+ if (unlikely(r != o))
+ *old = r;
+ return likely(r == o);
+}
+
+/**
+ * atomic_fetch_add() - atomic add
+ * @i: int value to add
+ * @v: pointer to atomic_t
+ *
+ * Atomically updates @v to (@v + @i).
+ *
+ * Return: The original value of @v.
+ */
+static __always_inline int
+atomic_fetch_add(int i, atomic_t *v)
+{
+ int old = v->counter;
+ v->counter += i;
+ return old;
+}
+#define atomic_fetch_add_relaxed atomic_fetch_add
+#define atomic_fetch_sub(i, v) atomic_fetch_add(-i, v)
+#define atomic_fetch_sub_release atomic_fetch_sub
#endif
diff --git a/include/linux/kref.h b/include/linux/kref.h
new file mode 100644
index 000000000000..6add3d91da95
--- /dev/null
+++ b/include/linux/kref.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * kref.h - library routines for handling generic reference counted objects
+ *
+ * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2004 IBM Corp.
+ *
+ * based on kobject.h which was:
+ * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org>
+ * Copyright (C) 2002-2003 Open Source Development Labs
+ */
+
+#ifndef _KREF_H_
+#define _KREF_H_
+
+#include <linux/refcount.h>
+
+struct kref {
+ refcount_t refcount;
+};
+
+#define KREF_INIT(n) { .refcount = REFCOUNT_INIT(n), }
+
+/**
+ * kref_init - initialize object.
+ * @kref: object in question.
+ */
+static inline void kref_init(struct kref *kref)
+{
+ refcount_set(&kref->refcount, 1);
+}
+
+static inline unsigned int kref_read(const struct kref *kref)
+{
+ return refcount_read(&kref->refcount);
+}
+
+/**
+ * kref_get - increment refcount for object.
+ * @kref: object.
+ */
+static inline void kref_get(struct kref *kref)
+{
+ refcount_inc(&kref->refcount);
+}
+
+/**
+ * kref_put - decrement refcount for object.
+ * @kref: object.
+ * @release: pointer to the function that will clean up the object when the
+ * last reference to the object is released.
+ * This pointer is required, and it is not acceptable to pass kfree
+ * in as this function.
+ *
+ * Decrement the refcount, and if 0, call release().
+ * Return 1 if the object was removed, otherwise return 0. Beware, if this
+ * function returns 0, you still can not count on the kref from remaining in
+ * memory. Only use the return value if you want to see if the kref is now
+ * gone, not present.
+ */
+static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
+{
+ if (refcount_dec_and_test(&kref->refcount)) {
+ release(kref);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * kref_get_unless_zero - Increment refcount for object unless it is zero.
+ * @kref: object.
+ *
+ * Return non-zero if the increment succeeded. Otherwise return 0.
+ *
+ * This function is intended to simplify locking around refcounting for
+ * objects that can be looked up from a lookup structure, and which are
+ * removed from that lookup structure in the object destructor.
+ * Operations on such objects require at least a read lock around
+ * lookup + kref_get, and a write lock around kref_put + remove from lookup
+ * structure. Furthermore, RCU implementations become extremely tricky.
+ * With a lookup followed by a kref_get_unless_zero *with return value check*
+ * locking in the kref_put path can be deferred to the actual removal from
+ * the lookup structure and RCU lookups become trivial.
+ */
+static inline int __must_check kref_get_unless_zero(struct kref *kref)
+{
+ return refcount_inc_not_zero(&kref->refcount);
+}
+#endif /* _KREF_H_ */
diff --git a/include/linux/refcount.h b/include/linux/refcount.h
new file mode 100644
index 000000000000..81eed1bbadb3
--- /dev/null
+++ b/include/linux/refcount.h
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_REFCOUNT_H
+#define _LINUX_REFCOUNT_H
+
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/compiler.h>
+#include <linux/limits.h>
+
+/**
+ * typedef refcount_t - variant of atomic_t specialized for reference counts
+ * @refs: atomic_t counter field
+ *
+ * The counter saturates at REFCOUNT_SATURATED and will not move once
+ * there. This avoids wrapping the counter and causing 'spurious'
+ * use-after-free bugs.
+ */
+typedef struct refcount_struct {
+ atomic_t refs;
+} refcount_t;
+
+#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), }
+#define REFCOUNT_MAX INT_MAX
+#define REFCOUNT_SATURATED (INT_MIN / 2)
+
+enum refcount_saturation_type {
+ REFCOUNT_ADD_NOT_ZERO_OVF,
+ REFCOUNT_ADD_OVF,
+ REFCOUNT_ADD_UAF,
+ REFCOUNT_SUB_UAF,
+ REFCOUNT_DEC_LEAK,
+};
+
+void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t);
+
+/**
+ * refcount_set - set a refcount's value
+ * @r: the refcount
+ * @n: value to which the refcount will be set
+ */
+static inline void refcount_set(refcount_t *r, int n)
+{
+ atomic_set(&r->refs, n);
+}
+
+/**
+ * refcount_read - get a refcount's value
+ * @r: the refcount
+ *
+ * Return: the refcount's value
+ */
+static inline unsigned int refcount_read(const refcount_t *r)
+{
+ return atomic_read(&r->refs);
+}
+
+static inline __must_check bool __refcount_add_not_zero(int i, refcount_t *r, int *oldp)
+{
+ int old = refcount_read(r);
+
+ do {
+ if (!old)
+ break;
+ } while (!atomic_try_cmpxchg_relaxed(&r->refs, &old, old + i));
+
+ if (oldp)
+ *oldp = old;
+
+ if (unlikely(old < 0 || old + i < 0))
+ refcount_warn_saturate(r, REFCOUNT_ADD_NOT_ZERO_OVF);
+
+ return old;
+}
+
+/**
+ * refcount_add_not_zero - add a value to a refcount unless it is 0
+ * @i: the value to add to the refcount
+ * @r: the refcount
+ *
+ * Will saturate at REFCOUNT_SATURATED and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller has guaranteed the
+ * object memory to be stable (RCU, etc.). It does provide a control dependency
+ * and thereby orders future stores. See the comment on top.
+ *
+ * Use of this function is not recommended for the normal reference counting
+ * use case in which references are taken and released one at a time. In these
+ * cases, refcount_inc(), or one of its variants, should instead be used to
+ * increment a reference count.
+ *
+ * Return: false if the passed refcount is 0, true otherwise
+ */
+static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)
+{
+ return __refcount_add_not_zero(i, r, NULL);
+}
+
+static inline void __refcount_add(int i, refcount_t *r, int *oldp)
+{
+ int old = atomic_fetch_add_relaxed(i, &r->refs);
+
+ if (oldp)
+ *oldp = old;
+
+ if (unlikely(!old))
+ refcount_warn_saturate(r, REFCOUNT_ADD_UAF);
+ else if (unlikely(old < 0 || old + i < 0))
+ refcount_warn_saturate(r, REFCOUNT_ADD_OVF);
+}
+
+/**
+ * refcount_add - add a value to a refcount
+ * @i: the value to add to the refcount
+ * @r: the refcount
+ *
+ * Similar to atomic_add(), but will saturate at REFCOUNT_SATURATED and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller has guaranteed the
+ * object memory to be stable (RCU, etc.). It does provide a control dependency
+ * and thereby orders future stores. See the comment on top.
+ *
+ * Use of this function is not recommended for the normal reference counting
+ * use case in which references are taken and released one at a time. In these
+ * cases, refcount_inc(), or one of its variants, should instead be used to
+ * increment a reference count.
+ */
+static inline void refcount_add(int i, refcount_t *r)
+{
+ __refcount_add(i, r, NULL);
+}
+
+static inline __must_check bool __refcount_inc_not_zero(refcount_t *r, int *oldp)
+{
+ return __refcount_add_not_zero(1, r, oldp);
+}
+
+/**
+ * refcount_inc_not_zero - increment a refcount unless it is 0
+ * @r: the refcount to increment
+ *
+ * Similar to atomic_inc_not_zero(), but will saturate at REFCOUNT_SATURATED
+ * and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller has guaranteed the
+ * object memory to be stable (RCU, etc.). It does provide a control dependency
+ * and thereby orders future stores. See the comment on top.
+ *
+ * Return: true if the increment was successful, false otherwise
+ */
+static inline __must_check bool refcount_inc_not_zero(refcount_t *r)
+{
+ return __refcount_inc_not_zero(r, NULL);
+}
+
+static inline void __refcount_inc(refcount_t *r, int *oldp)
+{
+ __refcount_add(1, r, oldp);
+}
+
+/**
+ * refcount_inc - increment a refcount
+ * @r: the refcount to increment
+ *
+ * Similar to atomic_inc(), but will saturate at REFCOUNT_SATURATED and WARN.
+ *
+ * Provides no memory ordering, it is assumed the caller already has a
+ * reference on the object.
+ *
+ * Will WARN if the refcount is 0, as this represents a possible use-after-free
+ * condition.
+ */
+static inline void refcount_inc(refcount_t *r)
+{
+ __refcount_inc(r, NULL);
+}
+
+static inline __must_check bool __refcount_sub_and_test(int i, refcount_t *r, int *oldp)
+{
+ int old = atomic_fetch_sub_release(i, &r->refs);
+
+ if (oldp)
+ *oldp = old;
+
+ if (old == i)
+ return true;
+
+ if (unlikely(old < 0 || old - i < 0))
+ refcount_warn_saturate(r, REFCOUNT_SUB_UAF);
+
+ return false;
+}
+
+/**
+ * refcount_sub_and_test - subtract from a refcount and test if it is 0
+ * @i: amount to subtract from the refcount
+ * @r: the refcount
+ *
+ * Similar to atomic_dec_and_test(), but it will WARN, return false and
+ * ultimately leak on underflow and will fail to decrement when saturated
+ * at REFCOUNT_SATURATED.
+ *
+ * Provides release memory ordering, such that prior loads and stores are done
+ * before, and provides an acquire ordering on success such that free()
+ * must come after.
+ *
+ * Use of this function is not recommended for the normal reference counting
+ * use case in which references are taken and released one at a time. In these
+ * cases, refcount_dec(), or one of its variants, should instead be used to
+ * decrement a reference count.
+ *
+ * Return: true if the resulting refcount is 0, false otherwise
+ */
+static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)
+{
+ return __refcount_sub_and_test(i, r, NULL);
+}
+
+static inline __must_check bool __refcount_dec_and_test(refcount_t *r, int *oldp)
+{
+ return __refcount_sub_and_test(1, r, oldp);
+}
+
+/**
+ * refcount_dec_and_test - decrement a refcount and test if it is 0
+ * @r: the refcount
+ *
+ * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
+ * decrement when saturated at REFCOUNT_SATURATED.
+ *
+ * Provides release memory ordering, such that prior loads and stores are done
+ * before, and provides an acquire ordering on success such that free()
+ * must come after.
+ *
+ * Return: true if the resulting refcount is 0, false otherwise
+ */
+static inline __must_check bool refcount_dec_and_test(refcount_t *r)
+{
+ return __refcount_dec_and_test(r, NULL);
+}
+
+static inline void __refcount_dec(refcount_t *r, int *oldp)
+{
+ int old = atomic_fetch_sub_release(1, &r->refs);
+
+ if (oldp)
+ *oldp = old;
+
+ if (unlikely(old <= 1))
+ refcount_warn_saturate(r, REFCOUNT_DEC_LEAK);
+}
+
+/**
+ * refcount_dec - decrement a refcount
+ * @r: the refcount
+ *
+ * Similar to atomic_dec(), it will WARN on underflow and fail to decrement
+ * when saturated at REFCOUNT_SATURATED.
+ *
+ * Provides release memory ordering, such that prior loads and stores are done
+ * before.
+ */
+static inline void refcount_dec(refcount_t *r)
+{
+ __refcount_dec(r, NULL);
+}
+
+extern __must_check bool refcount_dec_if_one(refcount_t *r);
+extern __must_check bool refcount_dec_not_one(refcount_t *r);
+
+#endif /* _LINUX_REFCOUNT_H */
diff --git a/lib/Makefile b/lib/Makefile
index 2b577becc444..492dd53436ce 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_BAREBOX_LOGO) += logo/
obj-y += reed_solomon/
obj-$(CONFIG_RATP) += ratp.o
obj-y += list_sort.o
+obj-y += refcount.o
obj-y += int_sqrt.o
obj-y += parseopt.o
obj-y += clz_ctz.o
diff --git a/lib/refcount.c b/lib/refcount.c
new file mode 100644
index 000000000000..8c6f98b48032
--- /dev/null
+++ b/lib/refcount.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Out-of-line refcount functions.
+ */
+
+#include <linux/refcount.h>
+#include <linux/printk.h>
+
+#define REFCOUNT_WARN(str) WARN_ONCE(1, "refcount_t: " str ".\n")
+
+void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t)
+{
+ refcount_set(r, REFCOUNT_SATURATED);
+
+ switch (t) {
+ case REFCOUNT_ADD_NOT_ZERO_OVF:
+ REFCOUNT_WARN("saturated; leaking memory");
+ break;
+ case REFCOUNT_ADD_OVF:
+ REFCOUNT_WARN("saturated; leaking memory");
+ break;
+ case REFCOUNT_ADD_UAF:
+ REFCOUNT_WARN("addition on 0; use-after-free");
+ break;
+ case REFCOUNT_SUB_UAF:
+ REFCOUNT_WARN("underflow; use-after-free");
+ break;
+ case REFCOUNT_DEC_LEAK:
+ REFCOUNT_WARN("decrement hit 0; leaking memory");
+ break;
+ default:
+ REFCOUNT_WARN("unknown saturation event!?");
+ }
+}
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 03/18] bitops: split off linux/bits.h
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 01/18] include: provide linux/errno.h Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 02/18] include: add linux/refcount.h Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 04/18] include: import <linux/instruction_pointer.h> Ahmad Fatoum
` (14 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The bit definitions are split off in Linux into <linux/bits.h>, which
is included by <linux/bitops.h> and extended with bit operations.
Follow through in barebox to simplify porting kernel code and in future
to speed up the build a bit by avoiding pulling in the whole bitops.h,
when only needing macros like BIT().
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/linux/bitops.h | 21 +--------------------
include/linux/bits.h | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 20 deletions(-)
create mode 100644 include/linux/bits.h
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index a5f6ac6545ee..65061946130c 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -5,15 +5,9 @@
#include <linux/types.h>
#include <linux/const.h>
+#include <linux/bits.h>
#ifdef __KERNEL__
-#define BIT(nr) (UL(1) << (nr))
-#define BIT_ULL(nr) (ULL(1) << (nr))
-#define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG))
-#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
-#define BIT_ULL_MASK(nr) (ULL(1) << ((nr) % BITS_PER_LONG_LONG))
-#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG)
-#define BITS_PER_BYTE 8
#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long))
#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u64))
@@ -21,19 +15,6 @@
#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char))
#endif
-/*
- * Create a contiguous bitmask starting at bit position @l and ending at
- * position @h. For example
- * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
- */
-#define GENMASK(h, l) \
- (((~UL(0)) - (UL(1) << (l)) + 1) & \
- (~UL(0) >> (BITS_PER_LONG - 1 - (h))))
-
-#define GENMASK_ULL(h, l) \
- (((~ULL(0)) - (ULL(1) << (l)) + 1) & \
- (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h))))
-
#ifndef __ASSEMBLY__
/*
* Include this here because some architectures need generic_ffs/fls in
diff --git a/include/linux/bits.h b/include/linux/bits.h
new file mode 100644
index 000000000000..ea5dfa120102
--- /dev/null
+++ b/include/linux/bits.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_BITS_H
+#define __LINUX_BITS_H
+
+#include <linux/types.h>
+#include <linux/const.h>
+#include <asm/bitsperlong.h>
+
+#define BIT(nr) (UL(1) << (nr))
+#define BIT_ULL(nr) (ULL(1) << (nr))
+#define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define BIT_ULL_MASK(nr) (ULL(1) << ((nr) % BITS_PER_LONG_LONG))
+#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG)
+#define BITS_PER_BYTE 8
+
+/*
+ * Create a contiguous bitmask starting at bit position @l and ending at
+ * position @h. For example
+ * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
+ */
+#define GENMASK(h, l) \
+ (((~UL(0)) - (UL(1) << (l)) + 1) & \
+ (~UL(0) >> (BITS_PER_LONG - 1 - (h))))
+
+#define GENMASK_ULL(h, l) \
+ (((~ULL(0)) - (ULL(1) << (l)) + 1) & \
+ (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h))))
+
+#endif /* __LINUX_BITS_H */
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 04/18] include: import <linux/instruction_pointer.h>
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (2 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 03/18] bitops: split off linux/bits.h Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 05/18] asm-generic: split off typeconfused readl and friends Ahmad Fatoum
` (13 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
This header provides definitions for getting the instruction pointer and
the return address in a portable manner, which can be useful for
trace outputs where dump_stack would be overkill.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/linux/instruction_pointer.h | 11 +++++++++++
include/linux/kernel.h | 3 +--
2 files changed, 12 insertions(+), 2 deletions(-)
create mode 100644 include/linux/instruction_pointer.h
diff --git a/include/linux/instruction_pointer.h b/include/linux/instruction_pointer.h
new file mode 100644
index 000000000000..6564127a31ba
--- /dev/null
+++ b/include/linux/instruction_pointer.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_INSTRUCTION_POINTER_H
+#define _LINUX_INSTRUCTION_POINTER_H
+
+#define _RET_IP_ (unsigned long)__builtin_return_address(0)
+
+#ifndef _THIS_IP_
+#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
+#endif
+
+#endif /* _LINUX_INSTRUCTION_POINTER_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 0e4ba243915b..da6121888ebd 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -8,6 +8,7 @@
#include <linux/limits.h>
#include <linux/math64.h>
#include <linux/container_of.h>
+#include <linux/instruction_pointer.h>
#include <linux/minmax.h>
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
@@ -117,8 +118,6 @@ extern long long simple_strtoll(const char *,char **,unsigned int);
} \
)
-#define _RET_IP_ (unsigned long)__builtin_return_address(0)
-
extern const char hex_asc[];
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 05/18] asm-generic: split off typeconfused readl and friends
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (3 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 04/18] include: import <linux/instruction_pointer.h> Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-13 12:40 ` Sascha Hauer
2023-11-10 21:44 ` [PATCH 06/18] asm-generic: migrate relaxed helpers into asm-generic/io.h Ahmad Fatoum
` (12 subsequent siblings)
17 siblings, 1 reply; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The MMIO accessors in barebox like readl have the error prone
peculiarity of accepting integer arguments to pointers automatically,
which makes it easy to confuse address and data.
We will add an alternative less error-probe way for new code, so first
split off the typeconfused code into a separate file.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/asm-generic/io-typeconfused.h | 75 +++++++++++++++++++++++++++
include/asm-generic/io.h | 57 +-------------------
2 files changed, 76 insertions(+), 56 deletions(-)
create mode 100644 include/asm-generic/io-typeconfused.h
diff --git a/include/asm-generic/io-typeconfused.h b/include/asm-generic/io-typeconfused.h
new file mode 100644
index 000000000000..d25ed7db2473
--- /dev/null
+++ b/include/asm-generic/io-typeconfused.h
@@ -0,0 +1,75 @@
+/* Generic I/O port emulation, based on MN10300 code
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef __ASM_GENERIC_IO_TYPECONFUSED_H
+#define __ASM_GENERIC_IO_TYPECONFUSED_H
+
+#include <linux/string.h> /* for memset() and memcpy() */
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/*****************************************************************************/
+/*
+ * Unlike the definitions in <asm-generic/io.h>, these macros don't complain
+ * about integer arguments and just silently cast them to pointers. This is
+ * a common cause of bugs, but lots of existing code depends on this, so
+ * this header is provided as a transitory measure.
+ */
+
+#ifndef __raw_readb
+#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
+#endif
+
+#ifndef __raw_readw
+#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
+#endif
+
+#ifndef __raw_readl
+#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
+#endif
+
+#ifndef readb
+#define readb __raw_readb
+#endif
+
+#ifndef readw
+#define readw(addr) __le16_to_cpu(__raw_readw(addr))
+#endif
+
+#ifndef readl
+#define readl(addr) __le32_to_cpu(__raw_readl(addr))
+#endif
+
+#ifndef __raw_writeb
+#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
+#endif
+
+#ifndef __raw_writew
+#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
+#endif
+
+#ifndef __raw_writel
+#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
+#endif
+
+#ifndef writeb
+#define writeb __raw_writeb
+#endif
+
+#ifndef writew
+#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
+#endif
+
+#ifndef writel
+#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
+#endif
+
+#endif /* __ASM_GENERIC_IO_TYPECONFUSED_H */
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index ab439026928a..6383d71746f1 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -15,62 +15,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <asm/byteorder.h>
-
-/*****************************************************************************/
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the simple architectures, we just read/write the
- * memory location directly.
- */
-
-#ifndef __raw_readb
-#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
-#endif
-
-#ifndef __raw_readw
-#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
-#endif
-
-#ifndef __raw_readl
-#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
-#endif
-
-#ifndef readb
-#define readb __raw_readb
-#endif
-
-#ifndef readw
-#define readw(addr) __le16_to_cpu(__raw_readw(addr))
-#endif
-
-#ifndef readl
-#define readl(addr) __le32_to_cpu(__raw_readl(addr))
-#endif
-
-#ifndef __raw_writeb
-#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
-#endif
-
-#ifndef __raw_writew
-#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
-#endif
-
-#ifndef __raw_writel
-#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
-#endif
-
-#ifndef writeb
-#define writeb __raw_writeb
-#endif
-
-#ifndef writew
-#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
-#endif
-
-#ifndef writel
-#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
-#endif
+#include <asm-generic/io-typeconfused.h>
#ifdef CONFIG_64BIT
static inline u64 __raw_readq(const volatile void __iomem *addr)
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 05/18] asm-generic: split off typeconfused readl and friends
2023-11-10 21:44 ` [PATCH 05/18] asm-generic: split off typeconfused readl and friends Ahmad Fatoum
@ 2023-11-13 12:40 ` Sascha Hauer
0 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2023-11-13 12:40 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Fri, Nov 10, 2023 at 10:44:08PM +0100, Ahmad Fatoum wrote:
> The MMIO accessors in barebox like readl have the error prone
> peculiarity of accepting integer arguments to pointers automatically,
> which makes it easy to confuse address and data.
>
> We will add an alternative less error-probe way for new code, so first
s/error-probe/error-prone/
> split off the typeconfused code into a separate file.
>
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
> include/asm-generic/io-typeconfused.h | 75 +++++++++++++++++++++++++++
> include/asm-generic/io.h | 57 +-------------------
> 2 files changed, 76 insertions(+), 56 deletions(-)
> create mode 100644 include/asm-generic/io-typeconfused.h
>
> diff --git a/include/asm-generic/io-typeconfused.h b/include/asm-generic/io-typeconfused.h
> new file mode 100644
> index 000000000000..d25ed7db2473
> --- /dev/null
> +++ b/include/asm-generic/io-typeconfused.h
> @@ -0,0 +1,75 @@
> +/* Generic I/O port emulation, based on MN10300 code
> + *
> + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
> + * Written by David Howells (dhowells@redhat.com)
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public Licence
> + * as published by the Free Software Foundation; either version
> + * 2 of the Licence, or (at your option) any later version.
> + */
> +#ifndef __ASM_GENERIC_IO_TYPECONFUSED_H
> +#define __ASM_GENERIC_IO_TYPECONFUSED_H
> +
> +#include <linux/string.h> /* for memset() and memcpy() */
> +#include <linux/compiler.h>
> +#include <linux/types.h>
> +#include <asm/byteorder.h>
> +
> +/*****************************************************************************/
> +/*
> + * Unlike the definitions in <asm-generic/io.h>, these macros don't complain
> + * about integer arguments and just silently cast them to pointers. This is
> + * a common cause of bugs, but lots of existing code depends on this, so
> + * this header is provided as a transitory measure.
> + */
> +
> +#ifndef __raw_readb
> +#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
> +#endif
> +
> +#ifndef __raw_readw
> +#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
> +#endif
> +
> +#ifndef __raw_readl
> +#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
> +#endif
> +
> +#ifndef readb
> +#define readb __raw_readb
> +#endif
> +
> +#ifndef readw
> +#define readw(addr) __le16_to_cpu(__raw_readw(addr))
> +#endif
> +
> +#ifndef readl
> +#define readl(addr) __le32_to_cpu(__raw_readl(addr))
> +#endif
> +
> +#ifndef __raw_writeb
> +#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
> +#endif
> +
> +#ifndef __raw_writew
> +#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
> +#endif
> +
> +#ifndef __raw_writel
> +#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
> +#endif
> +
> +#ifndef writeb
> +#define writeb __raw_writeb
> +#endif
> +
> +#ifndef writew
> +#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
> +#endif
> +
> +#ifndef writel
> +#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
> +#endif
> +
> +#endif /* __ASM_GENERIC_IO_TYPECONFUSED_H */
> diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
> index ab439026928a..6383d71746f1 100644
> --- a/include/asm-generic/io.h
> +++ b/include/asm-generic/io.h
> @@ -15,62 +15,7 @@
> #include <linux/compiler.h>
> #include <linux/types.h>
> #include <asm/byteorder.h>
> -
> -/*****************************************************************************/
> -/*
> - * readX/writeX() are used to access memory mapped devices. On some
> - * architectures the memory mapped IO stuff needs to be accessed
> - * differently. On the simple architectures, we just read/write the
> - * memory location directly.
> - */
> -
> -#ifndef __raw_readb
> -#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
> -#endif
> -
> -#ifndef __raw_readw
> -#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
> -#endif
> -
> -#ifndef __raw_readl
> -#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
> -#endif
> -
> -#ifndef readb
> -#define readb __raw_readb
> -#endif
> -
> -#ifndef readw
> -#define readw(addr) __le16_to_cpu(__raw_readw(addr))
> -#endif
> -
> -#ifndef readl
> -#define readl(addr) __le32_to_cpu(__raw_readl(addr))
> -#endif
> -
> -#ifndef __raw_writeb
> -#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
> -#endif
> -
> -#ifndef __raw_writew
> -#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
> -#endif
> -
> -#ifndef __raw_writel
> -#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
> -#endif
> -
> -#ifndef writeb
> -#define writeb __raw_writeb
> -#endif
> -
> -#ifndef writew
> -#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
> -#endif
> -
> -#ifndef writel
> -#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
> -#endif
> +#include <asm-generic/io-typeconfused.h>
>
> #ifdef CONFIG_64BIT
> static inline u64 __raw_readq(const volatile void __iomem *addr)
> --
> 2.39.2
>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 06/18] asm-generic: migrate relaxed helpers into asm-generic/io.h
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (4 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 05/18] asm-generic: split off typeconfused readl and friends Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 07/18] include: add linux/io.h with strict prototypes Ahmad Fatoum
` (11 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
In preparation for having <io.h> be the include file for type confused
MMIO accessors and <linux/io.h> for typechecked accessors, let's move out
of <io.h> everything that's not directly related to the type confusion.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/asm-generic/io.h | 34 ++++++++++++++++++++++++++++++++++
include/io.h | 34 ----------------------------------
2 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 6383d71746f1..b118979ed1df 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -792,4 +792,38 @@ static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer,
#include <asm-generic/bitio.h>
+#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err)
+
+#ifndef readq_relaxed
+#define readq_relaxed(addr) readq(addr)
+#endif
+
+#ifndef readl_relaxed
+#define readl_relaxed(addr) readl(addr)
+#endif
+
+#ifndef readw_relaxed
+#define readw_relaxed(addr) readw(addr)
+#endif
+
+#ifndef readb_relaxed
+#define readb_relaxed(addr) readb(addr)
+#endif
+
+#ifndef writeq_relaxed
+#define writeq_relaxed(val, addr) writeq((val), (addr))
+#endif
+
+#ifndef writel_relaxed
+#define writel_relaxed(val, addr) writel((val), (addr))
+#endif
+
+#ifndef writew_relaxed
+#define writew_relaxed(val, addr) writew((val), (addr))
+#endif
+
+#ifndef writeb_relaxed
+#define writeb_relaxed(val, addr) writeb((val), (addr))
+#endif
+
#endif /* __ASM_GENERIC_IO_H */
diff --git a/include/io.h b/include/io.h
index 6a74246ea777..913002072240 100644
--- a/include/io.h
+++ b/include/io.h
@@ -4,38 +4,4 @@
#include <asm/io.h>
-#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err)
-
-#ifndef readq_relaxed
-#define readq_relaxed(addr) readq(addr)
-#endif
-
-#ifndef readl_relaxed
-#define readl_relaxed(addr) readl(addr)
-#endif
-
-#ifndef readw_relaxed
-#define readw_relaxed(addr) readw(addr)
-#endif
-
-#ifndef readb_relaxed
-#define readb_relaxed(addr) readb(addr)
-#endif
-
-#ifndef writeq_relaxed
-#define writeq_relaxed(val, addr) writeq((val), (addr))
-#endif
-
-#ifndef writel_relaxed
-#define writel_relaxed(val, addr) writel((val), (addr))
-#endif
-
-#ifndef writew_relaxed
-#define writew_relaxed(val, addr) writew((val), (addr))
-#endif
-
-#ifndef writeb_relaxed
-#define writeb_relaxed(val, addr) writeb((val), (addr))
-#endif
-
#endif /* __IO_H */
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 07/18] include: add linux/io.h with strict prototypes
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (5 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 06/18] asm-generic: migrate relaxed helpers into asm-generic/io.h Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 08/18] include: import Linux word-at-a-time.h Ahmad Fatoum
` (10 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Kernel code uses <linux/io.h> instead of <io.h>, which defines readl and
friends as functions with type checks instead of macros that just cast
everything to pointers. Let's provide <linux/io.h> to ease porting as
well and have it have the same semantics.
Eventually, we should be able to get switch <io.h> to include
<linux/io.h> once all in-tree users are migrated.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/asm-generic/io.h | 217 +++++++++++++++++++++++++++++++++++++--
include/linux/io.h | 9 ++
2 files changed, 218 insertions(+), 8 deletions(-)
create mode 100644 include/linux/io.h
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index b118979ed1df..123ad5488ffc 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -13,23 +13,224 @@
#include <linux/string.h> /* for memset() and memcpy() */
#include <linux/compiler.h>
+#include <linux/instruction_pointer.h>
#include <linux/types.h>
#include <asm/byteorder.h>
+
+#ifndef __LINUX_IO_STRICT_PROTOTYPES__
#include <asm-generic/io-typeconfused.h>
+#endif
+
+#define __io_br() barrier()
+#define __io_ar(v) barrier()
+#define __io_bw() barrier()
+#define __io_pbw() __io_bw()
+#define __io_paw() __io_aw()
+#define __io_aw() do { } while (0)
+#define __io_pbr() __io_br()
+#define __io_par(v) __io_ar(v)
+
+static inline void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
+ unsigned long caller_addr, unsigned long caller_addr0) {}
+static inline void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr,
+ unsigned long caller_addr, unsigned long caller_addr0) {}
+static inline void log_read_mmio(u8 width, const volatile void __iomem *addr,
+ unsigned long caller_addr, unsigned long caller_addr0) {}
+static inline void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr,
+ unsigned long caller_addr, unsigned long caller_addr0) {}
+
+/*
+ * __raw_{read,write}{b,w,l,q}() access memory in native endianness.
+ *
+ * On some architectures memory mapped IO needs to be accessed differently.
+ * On the simple architectures, we just read/write the memory location
+ * directly.
+ */
+
+#ifndef __raw_readb
+#define __raw_readb __raw_readb
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+ return *(const volatile u8 __force *)addr;
+}
+#endif
+
+#ifndef __raw_readw
+#define __raw_readw __raw_readw
+static inline u16 __raw_readw(const volatile void __iomem *addr)
+{
+ return *(const volatile u16 __force *)addr;
+}
+#endif
+
+#ifndef __raw_readl
+#define __raw_readl __raw_readl
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+ return *(const volatile u32 __force *)addr;
+}
+#endif
#ifdef CONFIG_64BIT
+#ifndef __raw_readq
+#define __raw_readq __raw_readq
static inline u64 __raw_readq(const volatile void __iomem *addr)
{
- return *(const volatile u64 __force *) addr;
+ return *(const volatile u64 __force *)addr;
}
-#define readq(addr) __le64_to_cpu(__raw_readq(addr))
-
-static inline void __raw_writeq(u64 b, volatile void __iomem *addr)
-{
- *(volatile u64 __force *) addr = b;
-}
-#define writeq(b,addr) __raw_writeq(__cpu_to_le64(b),addr)
#endif
+#endif /* CONFIG_64BIT */
+
+#ifndef __raw_writeb
+#define __raw_writeb __raw_writeb
+static inline void __raw_writeb(u8 value, volatile void __iomem *addr)
+{
+ *(volatile u8 __force *)addr = value;
+}
+#endif
+
+#ifndef __raw_writew
+#define __raw_writew __raw_writew
+static inline void __raw_writew(u16 value, volatile void __iomem *addr)
+{
+ *(volatile u16 __force *)addr = value;
+}
+#endif
+
+#ifndef __raw_writel
+#define __raw_writel __raw_writel
+static inline void __raw_writel(u32 value, volatile void __iomem *addr)
+{
+ *(volatile u32 __force *)addr = value;
+}
+#endif
+
+#ifdef CONFIG_64BIT
+#ifndef __raw_writeq
+#define __raw_writeq __raw_writeq
+static inline void __raw_writeq(u64 value, volatile void __iomem *addr)
+{
+ *(volatile u64 __force *)addr = value;
+}
+#endif
+#endif /* CONFIG_64BIT */
+
+/*
+ * {read,write}{b,w,l,q}() access little endian memory and return result in
+ * native endianness.
+ */
+
+#ifndef readb
+#define readb readb
+static inline u8 readb(const volatile void __iomem *addr)
+{
+ u8 val;
+
+ log_read_mmio(8, addr, _THIS_IP_, _RET_IP_);
+ __io_br();
+ val = __raw_readb(addr);
+ __io_ar(val);
+ log_post_read_mmio(val, 8, addr, _THIS_IP_, _RET_IP_);
+ return val;
+}
+#endif
+
+#ifndef readw
+#define readw readw
+static inline u16 readw(const volatile void __iomem *addr)
+{
+ u16 val;
+
+ log_read_mmio(16, addr, _THIS_IP_, _RET_IP_);
+ __io_br();
+ val = __le16_to_cpu((__le16 __force)__raw_readw(addr));
+ __io_ar(val);
+ log_post_read_mmio(val, 16, addr, _THIS_IP_, _RET_IP_);
+ return val;
+}
+#endif
+
+#ifndef readl
+#define readl readl
+static inline u32 readl(const volatile void __iomem *addr)
+{
+ u32 val;
+
+ log_read_mmio(32, addr, _THIS_IP_, _RET_IP_);
+ __io_br();
+ val = __le32_to_cpu((__le32 __force)__raw_readl(addr));
+ __io_ar(val);
+ log_post_read_mmio(val, 32, addr, _THIS_IP_, _RET_IP_);
+ return val;
+}
+#endif
+
+#ifdef CONFIG_64BIT
+#ifndef readq
+#define readq readq
+static inline u64 readq(const volatile void __iomem *addr)
+{
+ u64 val;
+
+ log_read_mmio(64, addr, _THIS_IP_, _RET_IP_);
+ __io_br();
+ val = __le64_to_cpu((__le64 __force)__raw_readq(addr));
+ __io_ar(val);
+ log_post_read_mmio(val, 64, addr, _THIS_IP_, _RET_IP_);
+ return val;
+}
+#endif
+#endif /* CONFIG_64BIT */
+
+#ifndef writeb
+#define writeb writeb
+static inline void writeb(u8 value, volatile void __iomem *addr)
+{
+ log_write_mmio(value, 8, addr, _THIS_IP_, _RET_IP_);
+ __io_bw();
+ __raw_writeb(value, addr);
+ __io_aw();
+ log_post_write_mmio(value, 8, addr, _THIS_IP_, _RET_IP_);
+}
+#endif
+
+#ifndef writew
+#define writew writew
+static inline void writew(u16 value, volatile void __iomem *addr)
+{
+ log_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_);
+ __io_bw();
+ __raw_writew((u16 __force)cpu_to_le16(value), addr);
+ __io_aw();
+ log_post_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_);
+}
+#endif
+
+#ifndef writel
+#define writel writel
+static inline void writel(u32 value, volatile void __iomem *addr)
+{
+ log_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_);
+ __io_bw();
+ __raw_writel((u32 __force)__cpu_to_le32(value), addr);
+ __io_aw();
+ log_post_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_);
+}
+#endif
+
+#ifdef CONFIG_64BIT
+#ifndef writeq
+#define writeq writeq
+static inline void writeq(u64 value, volatile void __iomem *addr)
+{
+ log_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_);
+ __io_bw();
+ __raw_writeq((u64 __force)__cpu_to_le64(value), addr);
+ __io_aw();
+ log_post_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_);
+}
+#endif
+#endif /* CONFIG_64BIT */
#ifndef PCI_IOBASE
#define PCI_IOBASE ((void __iomem *)RELOC_HIDE((void *)0, 0))
diff --git a/include/linux/io.h b/include/linux/io.h
new file mode 100644
index 000000000000..9119e4e629d7
--- /dev/null
+++ b/include/linux/io.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _LINUX_IO_H
+#define _LINUX_IO_H
+
+#define __LINUX_IO_STRICT_PROTOTYPES__
+#include <asm/io.h>
+
+#endif
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 08/18] include: import Linux word-at-a-time.h
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (6 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 07/18] include: add linux/io.h with strict prototypes Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 09/18] string: implement strscpy Ahmad Fatoum
` (9 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The Linux <linux/word-at-a-time.h> interface is used to optimize
searching for bytes in strings by doing word-size comparisons. This will
be used in the implementation of strscpy in a follow-up commit, so
import the generic version here.
A good overview on the interface is available at LWN[1]. Note that
it discuss Linux v3.5. The asm-generic version imported here works
also on little-endian and not only big-endian[2].
[1]: https://lwn.net/Articles/501492/
[2]: Linux kernel commit a6e2f029ae34 ("Make asm/word-at-a-time.h
available on all architectures").
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/include/asm/word-at-a-time.h | 59 ++++++++
arch/kvx/include/asm/word-at-a-time.h | 2 +
arch/mips/include/asm/word-at-a-time.h | 2 +
arch/openrisc/include/asm/word-at-a-time.h | 2 +
arch/powerpc/include/asm/word-at-a-time.h | 156 +++++++++++++++++++++
arch/riscv/include/asm/word-at-a-time.h | 48 +++++++
arch/sandbox/include/asm/word-at-a-time.h | 2 +
arch/x86/include/asm/word-at-a-time.h | 73 ++++++++++
include/asm-generic/word-at-a-time.h | 121 ++++++++++++++++
include/linux/kernel.h | 8 ++
10 files changed, 473 insertions(+)
create mode 100644 arch/arm/include/asm/word-at-a-time.h
create mode 100644 arch/kvx/include/asm/word-at-a-time.h
create mode 100644 arch/mips/include/asm/word-at-a-time.h
create mode 100644 arch/openrisc/include/asm/word-at-a-time.h
create mode 100644 arch/powerpc/include/asm/word-at-a-time.h
create mode 100644 arch/riscv/include/asm/word-at-a-time.h
create mode 100644 arch/sandbox/include/asm/word-at-a-time.h
create mode 100644 arch/x86/include/asm/word-at-a-time.h
create mode 100644 include/asm-generic/word-at-a-time.h
diff --git a/arch/arm/include/asm/word-at-a-time.h b/arch/arm/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f22198a66be3
--- /dev/null
+++ b/arch/arm/include/asm/word-at-a-time.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 ARM Ltd.
+ */
+#ifndef __ASM_WORD_AT_A_TIME_H
+#define __ASM_WORD_AT_A_TIME_H
+
+#if !defined(__AARCH64EB__) && !defined(__ARMEB__)
+
+#include <linux/kernel.h>
+
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits,
+ const struct word_at_a_time *c)
+{
+ unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+#define prep_zero_mask(a, bits, c) (bits)
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ unsigned long ret;
+
+#if __LINUX_ARM_ARCH__ >= 8
+ ret = fls64(mask) >> 3;
+#elif __LINUX_ARM_ARCH__ >= 5
+ /* We have clz available. */
+ ret = fls(mask) >> 3;
+#else
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ ret = (0x0ff0001 + mask) >> 23;
+ /* Fix the 1 for 00 case */
+ ret &= mask;
+#endif
+
+ return ret;
+}
+
+#define zero_bytemask(mask) (mask)
+
+#else /* __AARCH64EB__ || __ARMEB__ */
+#include <asm-generic/word-at-a-time.h>
+#endif
+
+#endif /* __ASM_WORD_AT_A_TIME_H */
diff --git a/arch/kvx/include/asm/word-at-a-time.h b/arch/kvx/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f6306fb896a1
--- /dev/null
+++ b/arch/kvx/include/asm/word-at-a-time.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm-generic/word-at-a-time.h>
diff --git a/arch/mips/include/asm/word-at-a-time.h b/arch/mips/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f6306fb896a1
--- /dev/null
+++ b/arch/mips/include/asm/word-at-a-time.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm-generic/word-at-a-time.h>
diff --git a/arch/openrisc/include/asm/word-at-a-time.h b/arch/openrisc/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f6306fb896a1
--- /dev/null
+++ b/arch/openrisc/include/asm/word-at-a-time.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm-generic/word-at-a-time.h>
diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..1de46fbd2e15
--- /dev/null
+++ b/arch/powerpc/include/asm/word-at-a-time.h
@@ -0,0 +1,156 @@
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+/*
+ * Word-at-a-time interfaces for PowerPC.
+ */
+
+#include <linux/kernel.h>
+
+#ifdef __BIG_ENDIAN__
+
+struct word_at_a_time {
+ const unsigned long high_bits, low_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) }
+
+/* Bit set in the bytes that have a zero */
+static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c)
+{
+ unsigned long mask = (val & c->low_bits) + c->low_bits;
+ return ~(mask | rhs);
+}
+
+#define create_zero_mask(mask) (mask)
+
+static inline long find_zero(unsigned long mask)
+{
+ long leading_zero_bits;
+
+ asm (PPC_CNTLZL "%0,%1" : "=r" (leading_zero_bits) : "r" (mask));
+ return leading_zero_bits >> 3;
+}
+
+static inline unsigned long has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
+{
+ unsigned long rhs = val | c->low_bits;
+ *data = rhs;
+ return (val + c->high_bits) & ~rhs;
+}
+
+static inline unsigned long zero_bytemask(unsigned long mask)
+{
+ return ~1ul << __fls(mask);
+}
+
+#else
+
+#ifdef CONFIG_64BIT
+
+/* unused */
+struct word_at_a_time {
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { }
+
+/* This will give us 0xff for a NULL char and 0x00 elsewhere */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long ret;
+ unsigned long zero = 0;
+
+ asm("cmpb %0,%1,%2" : "=r" (ret) : "r" (a), "r" (zero));
+ *bits = ret;
+
+ return ret;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+/* Alan Modra's little-endian strlen tail for 64-bit */
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ unsigned long leading_zero_bits;
+ long trailing_zero_bit_mask;
+
+ asm("addi %1,%2,-1\n\t"
+ "andc %1,%1,%2\n\t"
+ "popcntd %0,%1"
+ : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask)
+ : "b" (bits));
+
+ return leading_zero_bits;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return mask >> 3;
+}
+
+/* This assumes that we never ask for an all 1s bitmask */
+static inline unsigned long zero_bytemask(unsigned long mask)
+{
+ return (1UL << mask) - 1;
+}
+
+#else /* 32-bit case */
+
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+/*
+ * This is largely generic for little-endian machines, but the
+ * optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ long a = (0x0ff0001+mask) >> 23;
+ /* Fix the 1 for 00 case */
+ return a & mask;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return count_masked_bytes(mask);
+}
+
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+#endif /* CONFIG_64BIT */
+
+#endif /* __BIG_ENDIAN__ */
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/arch/riscv/include/asm/word-at-a-time.h b/arch/riscv/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..7c086ac6ecd4
--- /dev/null
+++ b/arch/riscv/include/asm/word-at-a-time.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2012 Regents of the University of California
+ *
+ * Derived from arch/x86/include/asm/word-at-a-time.h
+ */
+
+#ifndef _ASM_RISCV_WORD_AT_A_TIME_H
+#define _ASM_RISCV_WORD_AT_A_TIME_H
+
+
+#include <linux/kernel.h>
+
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+static inline unsigned long has_zero(unsigned long val,
+ unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long mask = ((val - c->one_bits) & ~val) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long val,
+ unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return fls64(mask) >> 3;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+#endif /* _ASM_RISCV_WORD_AT_A_TIME_H */
diff --git a/arch/sandbox/include/asm/word-at-a-time.h b/arch/sandbox/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..f6306fb896a1
--- /dev/null
+++ b/arch/sandbox/include/asm/word-at-a-time.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm-generic/word-at-a-time.h>
diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h
new file mode 100644
index 000000000000..a7e57b7fd617
--- /dev/null
+++ b/arch/x86/include/asm/word-at-a-time.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+#include <linux/kernel.h>
+
+/*
+ * This is largely generic for little-endian machines, but the
+ * optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+ return mask*0x0001020304050608ul >> 56;
+}
+
+#else /* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ long a = (0x0ff0001+mask) >> 23;
+ /* Fix the 1 for 00 case */
+ return a & mask;
+}
+
+#endif
+
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return count_masked_bytes(mask);
+}
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
new file mode 100644
index 000000000000..95a1d214108a
--- /dev/null
+++ b/include/asm-generic/word-at-a-time.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+#include <linux/kernel.h>
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN
+
+struct word_at_a_time {
+ const unsigned long high_bits, low_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) }
+
+/* Bit set in the bytes that have a zero */
+static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c)
+{
+ unsigned long mask = (val & c->low_bits) + c->low_bits;
+ return ~(mask | rhs);
+}
+
+#define create_zero_mask(mask) (mask)
+
+static inline long find_zero(unsigned long mask)
+{
+ long byte = 0;
+#ifdef CONFIG_64BIT
+ if (mask >> 32)
+ mask >>= 32;
+ else
+ byte = 4;
+#endif
+ if (mask >> 16)
+ mask >>= 16;
+ else
+ byte += 2;
+ return (mask >> 8) ? byte : byte + 1;
+}
+
+static inline unsigned long has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
+{
+ unsigned long rhs = val | c->low_bits;
+ *data = rhs;
+ return (val + c->high_bits) & ~rhs;
+}
+
+#ifndef zero_bytemask
+#define zero_bytemask(mask) (~1ul << __fls(mask))
+#endif
+
+#else
+
+/*
+ * The optimal byte mask counting is probably going to be something
+ * that is architecture-specific. If you have a reliably fast
+ * bit count instruction, that might be better than the multiply
+ * and shift, for example.
+ */
+struct word_at_a_time {
+ const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
+
+#ifdef CONFIG_64BIT
+
+/*
+ * Jan Achrenius on G+: microoptimized version of
+ * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56"
+ * that works for the bytemasks without having to
+ * mask them first.
+ */
+static inline long count_masked_bytes(unsigned long mask)
+{
+ return mask*0x0001020304050608ul >> 56;
+}
+
+#else /* 32-bit case */
+
+/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
+static inline long count_masked_bytes(long mask)
+{
+ /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
+ long a = (0x0ff0001+mask) >> 23;
+ /* Fix the 1 for 00 case */
+ return a & mask;
+}
+
+#endif
+
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+ unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
+ *bits = mask;
+ return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+ return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+ bits = (bits - 1) & ~bits;
+ return bits >> 7;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+static inline unsigned long find_zero(unsigned long mask)
+{
+ return count_masked_bytes(mask);
+}
+
+#endif /* __BIG_ENDIAN */
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index da6121888ebd..4e50f6075189 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -11,6 +11,14 @@
#include <linux/instruction_pointer.h>
#include <linux/minmax.h>
+/**
+ * REPEAT_BYTE - repeat the value @x multiple times as an unsigned long value
+ * @x: value to repeat
+ *
+ * NOTE: @x is not checked for > 0xff; larger values produce odd results.
+ */
+#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x))
+
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
#define ALIGN_DOWN(x, a) ALIGN((x) - ((a) - 1), (a))
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 09/18] string: implement strscpy
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (7 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 08/18] include: import Linux word-at-a-time.h Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 10/18] of: add CONFIG_OF for Linux compatibility Ahmad Fatoum
` (8 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
strscpy is meant to be a safer alternative to strscpy, which always
terminates the destination string and returns an error code if
truncation happens. To enable porting kernel code using it, import the
definition.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/linux/string.h | 3 ++
lib/string.c | 71 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+)
diff --git a/include/linux/string.h b/include/linux/string.h
index 75c8cf818b39..32ce56939699 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -46,6 +46,9 @@ extern char * strncpy(char *,const char *, __kernel_size_t);
#ifndef __HAVE_ARCH_STRLCPY
size_t strlcpy(char *, const char *, size_t);
#endif
+#ifndef __HAVE_ARCH_STRSCPY
+ssize_t strscpy(char *, const char *, size_t);
+#endif
#ifndef __HAVE_ARCH_STRCAT
extern char * strcat(char *, const char *);
#endif
diff --git a/lib/string.c b/lib/string.c
index 166ef190d6aa..bf0f0455ab3f 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <string.h>
#include <linux/ctype.h>
+#include <asm/word-at-a-time.h>
#include <malloc.h>
#ifndef __HAVE_ARCH_STRCASECMP
@@ -87,6 +88,76 @@ char * strcpy(char * dest,const char *src)
#endif
EXPORT_SYMBOL(strcpy);
+#ifndef __HAVE_ARCH_STRSCPY
+ssize_t strscpy(char *dest, const char *src, size_t count)
+{
+ const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+ size_t max = count;
+ long res = 0;
+
+ if (count == 0 || WARN_ON_ONCE(count > INT_MAX))
+ return -E2BIG;
+
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ /*
+ * If src is unaligned, don't cross a page boundary,
+ * since we don't know if the next page is mapped.
+ */
+ if ((long)src & (sizeof(long) - 1)) {
+ size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1));
+ if (limit < max)
+ max = limit;
+ }
+#else
+ /* If src or dest is unaligned, don't do word-at-a-time. */
+ if (((long) dest | (long) src) & (sizeof(long) - 1))
+ max = 0;
+#endif
+
+ /*
+ * read_word_at_a_time() below may read uninitialized bytes after the
+ * trailing zero and use them in comparisons. Disable this optimization
+ * under KMSAN to prevent false positive reports.
+ */
+ if (IS_ENABLED(CONFIG_KMSAN))
+ max = 0;
+
+ while (max >= sizeof(unsigned long)) {
+ unsigned long c, data;
+
+ c = read_word_at_a_time(src+res);
+ if (has_zero(c, &data, &constants)) {
+ data = prep_zero_mask(c, data, &constants);
+ data = create_zero_mask(data);
+ *(unsigned long *)(dest+res) = c & zero_bytemask(data);
+ return res + find_zero(data);
+ }
+ *(unsigned long *)(dest+res) = c;
+ res += sizeof(unsigned long);
+ count -= sizeof(unsigned long);
+ max -= sizeof(unsigned long);
+ }
+
+ while (count) {
+ char c;
+
+ c = src[res];
+ dest[res] = c;
+ if (!c)
+ return res;
+ res++;
+ count--;
+ }
+
+ /* Hit buffer length without finding a NUL; force NUL-termination. */
+ if (res)
+ dest[res-1] = '\0';
+
+ return -E2BIG;
+}
+EXPORT_SYMBOL(strscpy);
+#endif
+
/**
* stpcpy - Copy a %NUL terminated string, but return pointer to %NUL
* @dest: Where to copy the string to
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 10/18] of: add CONFIG_OF for Linux compatibility
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (8 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 09/18] string: implement strscpy Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 11/18] include: asm-generic/atomic.h: define atomic_cmpxchg Ahmad Fatoum
` (7 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
barebox has CONFIG_OFTREE and CONFIG_OFDEVICE as separate definitions
for good reason, because configurations parsing device trees, while not
using them are possible. In Linux, there is no such distinction and
CONFIG_OF is used as single option for this. Provide the same option in
barebox as hidden symbol and select it from CONFIG_OFDEVICE to make
porting a tiny bit easier.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/of/Kconfig | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 4dc40b27f442..816aff0063b0 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -11,8 +11,12 @@ config OFTREE_MEM_GENERIC
config DTC
bool
+config OF
+ bool
+
config OFDEVICE
select OFTREE
+ select OF
select DTC
bool "Enable probing of devices from the devicetree"
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 11/18] include: asm-generic/atomic.h: define atomic_cmpxchg
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (9 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 10/18] of: add CONFIG_OF for Linux compatibility Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 12/18] kbuild: build barebox for -std=gnu11 Ahmad Fatoum
` (6 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We already define a generic cmpxchg implementation, so add one that
operates on atomic_t as well.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/asm-generic/atomic.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index 27b0f73b487b..74429e1c373f 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -116,6 +116,8 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
*addr &= ~mask;
}
+#define atomic_cmpxchg(v, o, n) cmpxchg(&((v)->counter), o, n)
+
/* Atomic operations are already serializing on ARM */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 12/18] kbuild: build barebox for -std=gnu11
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (10 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 11/18] include: asm-generic/atomic.h: define atomic_cmpxchg Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 13/18] include: linux/idr.h: implement more Linux API Ahmad Fatoum
` (5 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Linux has been configured with -std=gnu11 since v5.18 to benefit from
being able to declare variables in for loops init statements.
This is handy for barebox as well and should we adopt
__attribute__((cleanup)) to simplify resource management, it will become
required anyway, because define __attribute((cleanup)) variables much
earlier than they are used is needlessly cumbersome.
So let's do the switch.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index dc22ea546428..85bc6515d462 100644
--- a/Makefile
+++ b/Makefile
@@ -387,7 +387,7 @@ HOSTCC = gcc
HOSTCXX = g++
KBUILD_USERHOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \
- -O2 -fomit-frame-pointer -std=gnu89
+ -O2 -fomit-frame-pointer -std=gnu11
KBUILD_USERCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(USERCFLAGS)
KBUILD_USERLDFLAGS := $(USERLDFLAGS)
@@ -452,7 +452,7 @@ KBUILD_CPPFLAGS := -D__KERNEL__ -D__BAREBOX__ $(LINUXINCLUDE) -fno-builti
KBUILD_CFLAGS := -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs \
-fno-strict-aliasing -fno-common -fshort-wchar \
-Werror=implicit-function-declaration -Werror=implicit-int \
- -Os -pipe -Wmissing-prototypes -std=gnu89
+ -Os -pipe -Wmissing-prototypes -std=gnu11
KBUILD_AFLAGS := -D__ASSEMBLY__
KBUILD_AFLAGS_KERNEL :=
KBUILD_CFLAGS_KERNEL :=
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 13/18] include: linux/idr.h: implement more Linux API
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (11 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 12/18] kbuild: build barebox for -std=gnu11 Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 14/18] include: implement dev_warn_once and friends Ahmad Fatoum
` (4 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Upcoming sync of SCMI with the kernel will start using IDR API, which we
lack in barebox, so let's retrofit it.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/firmware/arm_scmi/driver.c | 2 +-
include/linux/idr.h | 69 ++++++++++++++++++++++++++----
2 files changed, 61 insertions(+), 10 deletions(-)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index dcd15528f394..c3536d6e9fbd 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1001,7 +1001,7 @@ int scmi_protocol_device_request(const struct scmi_device_id *id_table)
* Search for the matching protocol rdev list and then search
* of any existent equally named device...fails if any duplicate found.
*/
- __idr_for_each_entry(&scmi_requested_devices, idr) {
+ idr_for_each_entry(&scmi_requested_devices, idr) {
struct list_head *head = idr->ptr;
if (!phead) {
/* A list found registered in the IDR is never empty */
diff --git a/include/linux/idr.h b/include/linux/idr.h
index 12494b1f01cb..de1d5d78f546 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -24,21 +24,66 @@ struct idr {
#define DEFINE_IDR(name) \
struct idr name = { .list = LIST_HEAD_INIT((name).list) }
-#define __idr_for_each_entry(head, idr) \
- list_for_each_entry((idr), &(head)->list, list)
+/**
+ * idr_for_each_entry() - Iterate over an IDR's elements of a given type.
+ * @_idr: IDR handle.
+ * @_entry: The type * to use as cursor
+ * @_id: Entry ID.
+ *
+ * @_entry and @_id do not need to be initialized before the loop, and
+ * after normal termination @_entry is left with the value NULL. This
+ * is convenient for a "not found" value.
+ */
+#define idr_for_each_entry(_idr, _entry, _id) \
+ for (struct idr *iter = (_idr); \
+ &iter->list != &((_idr)->list) || (_entry = NULL); \
+ iter = list_next_entry(iter, list)) \
+ if ((_entry = iter->ptr, _id = iter->id, true))
-static inline struct idr *__idr_find(struct idr *head, int id)
+static inline struct idr *__idr_find(struct idr *head, int lookup_id)
{
- struct idr *idr;
+ struct idr *cursor;
- __idr_for_each_entry(head, idr) {
- if (idr->id == id)
- return idr;
+ list_for_each_entry(cursor, &head->list, list) {
+ if (cursor->id == lookup_id)
+ return cursor;
}
return NULL;
}
+/**
+ * idr_for_each() - Iterate through all stored pointers.
+ * @idr: IDR handle.
+ * @fn: Function to be called for each pointer.
+ * @data: Data passed to callback function.
+ *
+ * The callback function will be called for each entry in @idr, passing
+ * the ID, the entry and @data.
+ *
+ * If @fn returns anything other than %0, the iteration stops and that
+ * value is returned from this function.
+ */
+static inline int idr_for_each(const struct idr *idr,
+ int (*fn)(int id, void *p, void *data), void *data)
+{
+ const struct idr *pos, *tmp;
+ int ret;
+
+ list_for_each_entry_safe(pos, tmp, &idr->list, list) {
+ ret = fn(pos->id, pos->ptr, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline int idr_is_empty(const struct idr *idr)
+{
+ return list_empty(&idr->list);
+}
+
static inline void *idr_find(struct idr *head, int id)
{
struct idr *idr = __idr_find(head, id);
@@ -70,12 +115,18 @@ static inline void idr_init(struct idr *idr)
INIT_LIST_HEAD(&idr->list);
}
-static inline void idr_remove(struct idr *head, int id)
+static inline void idr_destroy(struct idr *idr)
{
- struct idr *idr = __idr_find(head, id);
+ if (!idr)
+ return;
list_del(&idr->list);
free(idr);
}
+static inline void idr_remove(struct idr *head, int id)
+{
+ idr_destroy(__idr_find(head, id));
+}
+
#endif /* __IDR_H__ */
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 14/18] include: implement dev_warn_once and friends
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (12 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 13/18] include: linux/idr.h: implement more Linux API Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-13 12:38 ` Sascha Hauer
2023-11-10 21:44 ` [PATCH 15/18] include: add blocking notifier aliases Ahmad Fatoum
` (3 subsequent siblings)
17 siblings, 1 reply; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We already have pr_once, so duplicate it for dev_warn and friends as
well.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/firmware/arm_scmi/driver.c | 4 ++--
include/linux/printk.h | 29 ++++++++++++++++++++++++++++-
2 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index c3536d6e9fbd..98f672746527 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -988,7 +988,7 @@ static void scmi_create_protocol_devices(struct device_node *np,
*/
int scmi_protocol_device_request(const struct scmi_device_id *id_table)
{
- int ret = 0;
+ int id, ret = 0;
struct list_head *phead = NULL;
struct scmi_requested_dev *rdev;
struct scmi_info *info;
@@ -1001,7 +1001,7 @@ int scmi_protocol_device_request(const struct scmi_device_id *id_table)
* Search for the matching protocol rdev list and then search
* of any existent equally named device...fails if any duplicate found.
*/
- idr_for_each_entry(&scmi_requested_devices, idr) {
+ idr_for_each_entry(&scmi_requested_devices, idr, id) {
struct list_head *head = idr->ptr;
if (!phead) {
/* A list found registered in the IDR is never empty */
diff --git a/include/linux/printk.h b/include/linux/printk.h
index cd4c3cb68edb..0e9604bbe967 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -57,7 +57,15 @@ static inline int pr_print(int level, const char *format, ...)
(level) <= LOGLEVEL ? dev_printf((level), (dev), (format), ##args) : 0; \
})
-
+#define __dev_printf_once(level, dev, format, args...) do { \
+ static bool __print_once; \
+ \
+ if (!__print_once && (level) <= LOGLEVEL) { \
+ __print_once = true; \
+ dev_printf((level), (dev), (format), ##args); \
+ } \
+} while (0)
+
#define dev_emerg(dev, format, arg...) \
__dev_printf(0, (dev) , format , ## arg)
#define dev_alert(dev, format, arg...) \
@@ -77,6 +85,25 @@ static inline int pr_print(int level, const char *format, ...)
#define dev_vdbg(dev, format, arg...) \
__dev_printf(8, (dev) , format , ## arg)
+#define dev_emerg_once(dev, format, arg...) \
+ __dev_printf_once(0, (dev) , format , ## arg)
+#define dev_alert_once(dev, format, arg...) \
+ __dev_printf_once(1, (dev) , format , ## arg)
+#define dev_crit_once(dev, format, arg...) \
+ __dev_printf_once(2, (dev) , format , ## arg)
+#define dev_err_once(dev, format, arg...) \
+ __dev_prin_oncetf(3, (dev) , format , ## arg)
+#define dev_warn_once(dev, format, arg...) \
+ __dev_printf_once(4, (dev) , format , ## arg)
+#define dev_notice_once(dev, format, arg...) \
+ __dev_printf(_once5, (dev) , format , ## arg)
+#define dev_info_once(dev, format, arg...) \
+ __dev_printf_once(6, (dev) , format , ## arg)
+#define dev_dbg_once(dev, format, arg...) \
+ __dev_prin_oncetf(7, (dev) , format , ## arg)
+#define dev_vdbg_once(dev, format, arg...) \
+ __dev_printf_once(8, (dev) , format , ## arg)
+
#if LOGLEVEL >= MSG_ERR
int dev_err_probe(struct device *dev, int err, const char *fmt, ...)
__attribute__ ((format(__printf__, 3, 4)));
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 14/18] include: implement dev_warn_once and friends
2023-11-10 21:44 ` [PATCH 14/18] include: implement dev_warn_once and friends Ahmad Fatoum
@ 2023-11-13 12:38 ` Sascha Hauer
0 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2023-11-13 12:38 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Fri, Nov 10, 2023 at 10:44:17PM +0100, Ahmad Fatoum wrote:
> We already have pr_once, so duplicate it for dev_warn and friends as
> well.
>
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
> drivers/firmware/arm_scmi/driver.c | 4 ++--
> include/linux/printk.h | 29 ++++++++++++++++++++++++++++-
> 2 files changed, 30 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
> index c3536d6e9fbd..98f672746527 100644
> --- a/drivers/firmware/arm_scmi/driver.c
> +++ b/drivers/firmware/arm_scmi/driver.c
> @@ -988,7 +988,7 @@ static void scmi_create_protocol_devices(struct device_node *np,
> */
> int scmi_protocol_device_request(const struct scmi_device_id *id_table)
> {
> - int ret = 0;
> + int id, ret = 0;
> struct list_head *phead = NULL;
> struct scmi_requested_dev *rdev;
> struct scmi_info *info;
> @@ -1001,7 +1001,7 @@ int scmi_protocol_device_request(const struct scmi_device_id *id_table)
> * Search for the matching protocol rdev list and then search
> * of any existent equally named device...fails if any duplicate found.
> */
> - idr_for_each_entry(&scmi_requested_devices, idr) {
> + idr_for_each_entry(&scmi_requested_devices, idr, id) {
> struct list_head *head = idr->ptr;
> if (!phead) {
> /* A list found registered in the IDR is never empty */
These changes should be part of an earlier patch, right?
Sascha
> diff --git a/include/linux/printk.h b/include/linux/printk.h
> index cd4c3cb68edb..0e9604bbe967 100644
> --- a/include/linux/printk.h
> +++ b/include/linux/printk.h
> @@ -57,7 +57,15 @@ static inline int pr_print(int level, const char *format, ...)
> (level) <= LOGLEVEL ? dev_printf((level), (dev), (format), ##args) : 0; \
> })
>
> -
> +#define __dev_printf_once(level, dev, format, args...) do { \
> + static bool __print_once; \
> + \
> + if (!__print_once && (level) <= LOGLEVEL) { \
> + __print_once = true; \
> + dev_printf((level), (dev), (format), ##args); \
> + } \
> +} while (0)
> +
> #define dev_emerg(dev, format, arg...) \
> __dev_printf(0, (dev) , format , ## arg)
> #define dev_alert(dev, format, arg...) \
> @@ -77,6 +85,25 @@ static inline int pr_print(int level, const char *format, ...)
> #define dev_vdbg(dev, format, arg...) \
> __dev_printf(8, (dev) , format , ## arg)
>
> +#define dev_emerg_once(dev, format, arg...) \
> + __dev_printf_once(0, (dev) , format , ## arg)
> +#define dev_alert_once(dev, format, arg...) \
> + __dev_printf_once(1, (dev) , format , ## arg)
> +#define dev_crit_once(dev, format, arg...) \
> + __dev_printf_once(2, (dev) , format , ## arg)
> +#define dev_err_once(dev, format, arg...) \
> + __dev_prin_oncetf(3, (dev) , format , ## arg)
> +#define dev_warn_once(dev, format, arg...) \
> + __dev_printf_once(4, (dev) , format , ## arg)
> +#define dev_notice_once(dev, format, arg...) \
> + __dev_printf(_once5, (dev) , format , ## arg)
> +#define dev_info_once(dev, format, arg...) \
> + __dev_printf_once(6, (dev) , format , ## arg)
> +#define dev_dbg_once(dev, format, arg...) \
> + __dev_prin_oncetf(7, (dev) , format , ## arg)
> +#define dev_vdbg_once(dev, format, arg...) \
> + __dev_printf_once(8, (dev) , format , ## arg)
> +
> #if LOGLEVEL >= MSG_ERR
> int dev_err_probe(struct device *dev, int err, const char *fmt, ...)
> __attribute__ ((format(__printf__, 3, 4)));
> --
> 2.39.2
>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 15/18] include: add blocking notifier aliases
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (13 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 14/18] include: implement dev_warn_once and friends Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-13 12:39 ` Sascha Hauer
2023-11-10 21:44 ` [PATCH 16/18] include: add Linux ktime API Ahmad Fatoum
` (2 subsequent siblings)
17 siblings, 1 reply; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
All notifiers are blocking in barebox, but to avoid needless mechanical
fixups during porting, just provide the stubs in a new
<linux/notifier.h> header. While at it, also provide NOTIFY_DONE and
NOTIFY_DONE for use in the notifier callbacks.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/linux/notifier.h | 16 ++++++++++++++++
include/notifier.h | 3 +++
2 files changed, 19 insertions(+)
create mode 100644 include/linux/notifier.h
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
new file mode 100644
index 000000000000..25f4921a3e80
--- /dev/null
+++ b/include/linux/notifier.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __LINUX_NOTIFIER_H
+#define __LINUX_NOTIFIER_H
+
+#include <notifier.h>
+
+#define BLOCKING_NOTIFIER_HEAD NOTIFIER_HEAD
+
+#define blocking_notifier_call_chain notifier_call_chain
+
+#define blocking_notifier_head notifier_head
+
+#define blocking_notifier_chain_register notifier_chain_register
+#define blocking_notifier_chain_unregister notifier_chain_unregister
+
+#endif
diff --git a/include/notifier.h b/include/notifier.h
index 432b66c4ca5a..093fedb0e8e4 100644
--- a/include/notifier.h
+++ b/include/notifier.h
@@ -35,4 +35,7 @@ int clock_notifier_call_chain(void);
.blocks = LIST_HEAD_INIT((name).blocks), \
};
+#define NOTIFY_DONE 0x0000 /* Don't care */
+#define NOTIFY_OK 0x0001 /* Suits me */
+
#endif /* __NOTIFIER_H */
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 15/18] include: add blocking notifier aliases
2023-11-10 21:44 ` [PATCH 15/18] include: add blocking notifier aliases Ahmad Fatoum
@ 2023-11-13 12:39 ` Sascha Hauer
0 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2023-11-13 12:39 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Fri, Nov 10, 2023 at 10:44:18PM +0100, Ahmad Fatoum wrote:
> All notifiers are blocking in barebox, but to avoid needless mechanical
> fixups during porting, just provide the stubs in a new
> <linux/notifier.h> header. While at it, also provide NOTIFY_DONE and
> NOTIFY_DONE for use in the notifier callbacks.
The 2nd NOTIFY_DONE s/NOTIFY_DONE/NOTIFY_OK/
Sascha
>
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
> include/linux/notifier.h | 16 ++++++++++++++++
> include/notifier.h | 3 +++
> 2 files changed, 19 insertions(+)
> create mode 100644 include/linux/notifier.h
>
> diff --git a/include/linux/notifier.h b/include/linux/notifier.h
> new file mode 100644
> index 000000000000..25f4921a3e80
> --- /dev/null
> +++ b/include/linux/notifier.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __LINUX_NOTIFIER_H
> +#define __LINUX_NOTIFIER_H
> +
> +#include <notifier.h>
> +
> +#define BLOCKING_NOTIFIER_HEAD NOTIFIER_HEAD
> +
> +#define blocking_notifier_call_chain notifier_call_chain
> +
> +#define blocking_notifier_head notifier_head
> +
> +#define blocking_notifier_chain_register notifier_chain_register
> +#define blocking_notifier_chain_unregister notifier_chain_unregister
> +
> +#endif
> diff --git a/include/notifier.h b/include/notifier.h
> index 432b66c4ca5a..093fedb0e8e4 100644
> --- a/include/notifier.h
> +++ b/include/notifier.h
> @@ -35,4 +35,7 @@ int clock_notifier_call_chain(void);
> .blocks = LIST_HEAD_INIT((name).blocks), \
> };
>
> +#define NOTIFY_DONE 0x0000 /* Don't care */
> +#define NOTIFY_OK 0x0001 /* Suits me */
> +
> #endif /* __NOTIFIER_H */
> --
> 2.39.2
>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 16/18] include: add Linux ktime API
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (14 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 15/18] include: add blocking notifier aliases Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 17/18] of: define of_devices_ensure_probed_by_compatible Ahmad Fatoum
2023-11-10 21:44 ` [PATCH 18/18] include: add linux/device.h wrapper around driver.h Ahmad Fatoum
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
With get_time_ns(), we already have a monotonically increasing nanosecond
counter, so let's define ktime_get() as an alias for it and import the
Linux helpers for doing arithmetic with this ktime_t type.
There is a slight mismatch here as get_time_ns() returns a u64, while
ktime_t is signed, but U64_MAX is > 580 years and half of that is still
a fair bit longer than the expected life time of a device idling with
100% CPU in the barebox shell after an aborted boot.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/linux/ktime.h | 212 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 212 insertions(+)
create mode 100644 include/linux/ktime.h
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
new file mode 100644
index 000000000000..ea368b8802e7
--- /dev/null
+++ b/include/linux/ktime.h
@@ -0,0 +1,212 @@
+/*
+ * include/linux/ktime.h
+ *
+ * ktime_t - nanosecond-resolution time format.
+ *
+ * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright(C) 2005, Red Hat, Inc., Ingo Molnar
+ *
+ * data type definitions, declarations, prototypes and macros.
+ *
+ * Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * Credits:
+ *
+ * Roman Zippel provided the ideas and primary code snippets of
+ * the ktime_t union and further simplifications of the original
+ * code.
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _LINUX_KTIME_H
+#define _LINUX_KTIME_H
+
+#include <linux/time.h>
+#include <clock.h>
+#include <linux/bug.h>
+
+#define KTIME_MAX ((s64)~((u64)1 << 63))
+#define KTIME_MIN (-KTIME_MAX - 1)
+#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
+#define KTIME_SEC_MIN (KTIME_MIN / NSEC_PER_SEC)
+
+/* Nanosecond scalar representation for kernel time values */
+typedef s64 ktime_t;
+
+/**
+ * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
+ * @secs: seconds to set
+ * @nsecs: nanoseconds to set
+ *
+ * Return: The ktime_t representation of the value.
+ */
+static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs)
+{
+ if (unlikely(secs >= KTIME_SEC_MAX))
+ return KTIME_MAX;
+
+ return secs * NSEC_PER_SEC + (s64)nsecs;
+}
+
+/* Subtract two ktime_t variables. rem = lhs -rhs: */
+#define ktime_sub(lhs, rhs) ((lhs) - (rhs))
+
+/* Add two ktime_t variables. res = lhs + rhs: */
+#define ktime_add(lhs, rhs) ((lhs) + (rhs))
+
+/*
+ * Same as ktime_add(), but avoids undefined behaviour on overflow; however,
+ * this means that you must check the result for overflow yourself.
+ */
+#define ktime_add_unsafe(lhs, rhs) ((u64) (lhs) + (rhs))
+
+/*
+ * Add a ktime_t variable and a scalar nanosecond value.
+ * res = kt + nsval:
+ */
+#define ktime_add_ns(kt, nsval) ((kt) + (nsval))
+
+/*
+ * Subtract a scalar nanosecod from a ktime_t variable
+ * res = kt - nsval:
+ */
+#define ktime_sub_ns(kt, nsval) ((kt) - (nsval))
+
+/* Convert ktime_t to nanoseconds */
+static inline s64 ktime_to_ns(const ktime_t kt)
+{
+ return kt;
+}
+
+/**
+ * ktime_compare - Compares two ktime_t variables for less, greater or equal
+ * @cmp1: comparable1
+ * @cmp2: comparable2
+ *
+ * Return: ...
+ * cmp1 < cmp2: return <0
+ * cmp1 == cmp2: return 0
+ * cmp1 > cmp2: return >0
+ */
+static inline int ktime_compare(const ktime_t cmp1, const ktime_t cmp2)
+{
+ if (cmp1 < cmp2)
+ return -1;
+ if (cmp1 > cmp2)
+ return 1;
+ return 0;
+}
+
+/**
+ * ktime_after - Compare if a ktime_t value is bigger than another one.
+ * @cmp1: comparable1
+ * @cmp2: comparable2
+ *
+ * Return: true if cmp1 happened after cmp2.
+ */
+static inline bool ktime_after(const ktime_t cmp1, const ktime_t cmp2)
+{
+ return ktime_compare(cmp1, cmp2) > 0;
+}
+
+/**
+ * ktime_before - Compare if a ktime_t value is smaller than another one.
+ * @cmp1: comparable1
+ * @cmp2: comparable2
+ *
+ * Return: true if cmp1 happened before cmp2.
+ */
+static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2)
+{
+ return ktime_compare(cmp1, cmp2) < 0;
+}
+
+#if BITS_PER_LONG < 64
+extern s64 __ktime_divns(const ktime_t kt, s64 div);
+static inline s64 ktime_divns(const ktime_t kt, s64 div)
+{
+ /*
+ * Negative divisors could cause an inf loop,
+ * so bug out here.
+ */
+ BUG_ON(div < 0);
+ if (__builtin_constant_p(div) && !(div >> 32)) {
+ s64 ns = kt;
+ u64 tmp = ns < 0 ? -ns : ns;
+
+ do_div(tmp, div);
+ return ns < 0 ? -tmp : tmp;
+ } else {
+ return __ktime_divns(kt, div);
+ }
+}
+#else /* BITS_PER_LONG < 64 */
+static inline s64 ktime_divns(const ktime_t kt, s64 div)
+{
+ /*
+ * 32-bit implementation cannot handle negative divisors,
+ * so catch them on 64bit as well.
+ */
+ WARN_ON(div < 0);
+ return kt / div;
+}
+#endif
+
+static inline s64 ktime_to_us(const ktime_t kt)
+{
+ return ktime_divns(kt, NSEC_PER_USEC);
+}
+
+static inline s64 ktime_to_ms(const ktime_t kt)
+{
+ return ktime_divns(kt, NSEC_PER_MSEC);
+}
+
+static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier)
+{
+ return ktime_to_us(ktime_sub(later, earlier));
+}
+
+static inline s64 ktime_ms_delta(const ktime_t later, const ktime_t earlier)
+{
+ return ktime_to_ms(ktime_sub(later, earlier));
+}
+
+static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec)
+{
+ return ktime_add_ns(kt, usec * NSEC_PER_USEC);
+}
+
+static inline ktime_t ktime_add_ms(const ktime_t kt, const u64 msec)
+{
+ return ktime_add_ns(kt, msec * NSEC_PER_MSEC);
+}
+
+static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec)
+{
+ return ktime_sub_ns(kt, usec * NSEC_PER_USEC);
+}
+
+static inline ktime_t ktime_sub_ms(const ktime_t kt, const u64 msec)
+{
+ return ktime_sub_ns(kt, msec * NSEC_PER_MSEC);
+}
+
+extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs);
+
+static inline ktime_t ns_to_ktime(u64 ns)
+{
+ return ns;
+}
+
+static inline ktime_t ms_to_ktime(u64 ms)
+{
+ return ms * NSEC_PER_MSEC;
+}
+
+static inline ktime_t ktime_get(void)
+{
+ return get_time_ns();
+}
+
+#endif
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 17/18] of: define of_devices_ensure_probed_by_compatible
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (15 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 16/18] include: add Linux ktime API Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
2023-11-13 12:47 ` Sascha Hauer
2023-11-10 21:44 ` [PATCH 18/18] include: add linux/device.h wrapper around driver.h Ahmad Fatoum
17 siblings, 1 reply; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We will need to ensure probe of OP-TEE from SCMI code in a follow-up
commit, so add a small helper to facilitate this.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/of.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/of.h b/include/of.h
index a7a1ce125fc0..7ebf1f02cc68 100644
--- a/include/of.h
+++ b/include/of.h
@@ -1220,6 +1220,16 @@ int of_device_disable(struct device_node *node);
int of_device_disable_path(const char *path);
int of_device_disable_by_alias(const char *alias);
+static inline int of_devices_ensure_probed_by_compatible(char *compatible)
+{
+ struct of_device_id match_id[] = {
+ { .compatible = compatible, },
+ { /* sentinel */ },
+ };
+
+ return of_devices_ensure_probed_by_dev_id(match_id);
+}
+
phandle of_get_tree_max_phandle(struct device_node *root);
phandle of_node_create_phandle(struct device_node *node);
int of_set_property_to_child_phandle(struct device_node *node, char *prop_name);
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 17/18] of: define of_devices_ensure_probed_by_compatible
2023-11-10 21:44 ` [PATCH 17/18] of: define of_devices_ensure_probed_by_compatible Ahmad Fatoum
@ 2023-11-13 12:47 ` Sascha Hauer
0 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2023-11-13 12:47 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Fri, Nov 10, 2023 at 10:44:20PM +0100, Ahmad Fatoum wrote:
> We will need to ensure probe of OP-TEE from SCMI code in a follow-up
> commit, so add a small helper to facilitate this.
>
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
> include/of.h | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/include/of.h b/include/of.h
> index a7a1ce125fc0..7ebf1f02cc68 100644
> --- a/include/of.h
> +++ b/include/of.h
> @@ -1220,6 +1220,16 @@ int of_device_disable(struct device_node *node);
> int of_device_disable_path(const char *path);
> int of_device_disable_by_alias(const char *alias);
>
> +static inline int of_devices_ensure_probed_by_compatible(char *compatible)
Should the argument be const char *?
We would have to change struct of_device_id::compatible to const char *
as well, but at least a test build of multi_v8_defconfig showed no
problems with this change.
Sascha
> +{
> + struct of_device_id match_id[] = {
> + { .compatible = compatible, },
> + { /* sentinel */ },
> + };
> +
> + return of_devices_ensure_probed_by_dev_id(match_id);
> +}
> +
> phandle of_get_tree_max_phandle(struct device_node *root);
> phandle of_node_create_phandle(struct device_node *node);
> int of_set_property_to_child_phandle(struct device_node *node, char *prop_name);
> --
> 2.39.2
>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 18/18] include: add linux/device.h wrapper around driver.h
2023-11-10 21:44 [PATCH 00/18] prepare for porting OP-TEE communication support Ahmad Fatoum
` (16 preceding siblings ...)
2023-11-10 21:44 ` [PATCH 17/18] of: define of_devices_ensure_probed_by_compatible Ahmad Fatoum
@ 2023-11-10 21:44 ` Ahmad Fatoum
17 siblings, 0 replies; 23+ messages in thread
From: Ahmad Fatoum @ 2023-11-10 21:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
We don't have device-scoped resource control and in practice memory
allocated in device functions is only freed when barebox terminates, so
let's accept the fact that most code is leaky and implement devm_
as literal leaky abstractions.
While at it provide some macros to translate Linux API into equivalent
barebox API.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/linux/device.h | 66 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 include/linux/device.h
diff --git a/include/linux/device.h b/include/linux/device.h
new file mode 100644
index 000000000000..0bd61154ac30
--- /dev/null
+++ b/include/linux/device.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LINUX_DRIVER_H_
+#define LINUX_DRIVER_H_
+
+#include <driver.h>
+#include <linux/slab.h>
+#include <linux/bug.h>
+#include <mmu.h>
+
+#define device_driver driver
+
+#define __devm_wrapper(fn, dev, ...) ({ BUG_ON(!dev); fn(__VA_ARGS__); })
+
+#define devm_kmalloc(...) __devm_wrapper(kmalloc, __VA_ARGS__)
+#define devm_krealloc(...) __devm_wrapper(krealloc, __VA_ARGS__)
+#define devm_kvasprintf(...) __devm_wrapper(kvasprintf, __VA_ARGS__)
+#define devm_kasprintf(...) __devm_wrapper(kasprintf, __VA_ARGS__)
+#define devm_kzalloc(...) __devm_wrapper(kzalloc, __VA_ARGS__)
+#define devm_kmalloc_array(...) __devm_wrapper(kmalloc_array, __VA_ARGS__)
+#define devm_kcalloc(...) __devm_wrapper(kcalloc, __VA_ARGS__)
+#define devm_krealloc_array(...) __devm_wrapper(krealloc_array, __VA_ARGS__)
+#define devm_kfree(...) __devm_wrapper(kfree, __VA_ARGS__)
+#define devm_kstrdup(...) __devm_wrapper(kstrdup, __VA_ARGS__)
+#define devm_kstrdup_const(...) __devm_wrapper(kstrdup_const, __VA_ARGS__)
+#define devm_kmemdup(...) __devm_wrapper(kmemdup, __VA_ARGS__)
+#define devm_bitmap_zalloc(dev, nbits, gfp) \
+ __devm_wrapper(bitmap_zalloc, dev, nbits)
+
+#define device_register register_device
+#define device_unregister unregister_device
+
+#define driver_register register_driver
+#define driver_unregister unregister_driver
+
+static inline void __iomem *devm_ioremap(struct device *dev,
+ resource_size_t start,
+ resource_size_t size)
+{
+ if (start)
+ remap_range((void *)start, size, MAP_UNCACHED);
+
+ return IOMEM(start);
+}
+
+static inline int bus_for_each_dev(const struct bus_type *bus, struct device *start, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct device *dev;
+ int ret;
+
+ bus_for_each_device(bus, dev) {
+ if (start) {
+ if (dev == start)
+ start = NULL;
+ continue;
+ }
+
+ ret = fn(dev, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+#endif
--
2.39.2
^ permalink raw reply [flat|nested] 23+ messages in thread