]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
compat: add kref implementation
authorCasey Connolly <casey.connolly@linaro.org>
Wed, 1 Apr 2026 14:15:22 +0000 (16:15 +0200)
committerTom Rini <trini@konsulko.com>
Tue, 21 Apr 2026 17:19:49 +0000 (11:19 -0600)
This is a very basic port of Linux' kref, we don't actually need atomics
so we just use a simple counter. This is used by CCF to free unused
clocks.

Signed-off-by: Casey Connolly <casey.connolly@linaro.org>
include/linux/kref.h [new file with mode: 0644]

diff --git a/include/linux/kref.h b/include/linux/kref.h
new file mode 100644 (file)
index 0000000..3092704
--- /dev/null
@@ -0,0 +1,124 @@
+/* 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/compat.h>
+
+struct kref {
+       long 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)
+{
+       kref->refcount = 1;
+}
+
+static inline unsigned int kref_read(const struct kref *kref)
+{
+       return kref->refcount;
+}
+
+/**
+ * kref_get - increment refcount for object.
+ * @kref: object.
+ */
+static inline void kref_get(struct kref *kref)
+{
+       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.
+ *
+ * Decrement the refcount, and if 0, call @release.  The caller may not
+ * pass NULL or kfree() as the release function.
+ *
+ * Return: 1 if this call removed the object, otherwise return 0.  Beware,
+ * if this function returns 0, another caller may have removed the object
+ * by the time this function returns.  The return value is only certain
+ * if you want to see if the object is definitely released.
+ */
+static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
+{
+       if (--kref->refcount == 0) {
+               release(kref);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * kref_put_mutex - 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.
+ * @mutex: Mutex which protects the release function.
+ *
+ * This variant of kref_lock() calls the @release function with the @mutex
+ * held.  The @release function will release the mutex.
+ */
+static inline int kref_put_mutex(struct kref *kref,
+                                void (*release)(struct kref *kref),
+                                struct mutex *mutex)
+{
+       return kref_put(kref, release);
+}
+
+/**
+ * kref_put_lock - 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.
+ * @lock: Spinlock which protects the release function.
+ *
+ * This variant of kref_lock() calls the @release function with the @lock
+ * held.  The @release function will release the lock.
+ */
+static inline int kref_put_lock(struct kref *kref,
+                               void (*release)(struct kref *kref),
+                               spinlock_t *lock)
+{
+       return kref_put(kref, release);
+}
+
+/**
+ * kref_get_unless_zero - Increment refcount for object unless it is zero.
+ * @kref: object.
+ *
+ * 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.
+ *
+ * Return: non-zero if the increment succeeded. Otherwise return 0.
+ */
+static inline int kref_get_unless_zero(struct kref *kref)
+{
+       return kref->refcount ? kref->refcount++ : 0;
+}
+#endif /* _KREF_H_ */