Module Name:    src
Committed By:   riastradh
Date:           Sun Dec 19 11:52:08 UTC 2021

Modified Files:
        src/sys/external/bsd/drm2/dist/drm/i915: i915_active.c
            i915_active_types.h
        src/sys/external/bsd/drm2/dist/drm/i915/gt: intel_engine_pm.c
        src/sys/external/bsd/drm2/i915drm: files.i915drmkms
        src/sys/external/bsd/drm2/include/linux: llist.h refcount.h spinlock.h

Log Message:
i915: intel_engine_pm.c and i915_active.c

...with a little less heinous abuse of C, and an attempt to
disentangle the tentacular abstraction violations rampant in these
components


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 \
    src/sys/external/bsd/drm2/dist/drm/i915/i915_active.c
cvs rdiff -u -r1.2 -r1.3 \
    src/sys/external/bsd/drm2/dist/drm/i915/i915_active_types.h
cvs rdiff -u -r1.2 -r1.3 \
    src/sys/external/bsd/drm2/dist/drm/i915/gt/intel_engine_pm.c
cvs rdiff -u -r1.82 -r1.83 src/sys/external/bsd/drm2/i915drm/files.i915drmkms
cvs rdiff -u -r1.5 -r1.6 src/sys/external/bsd/drm2/include/linux/llist.h
cvs rdiff -u -r1.2 -r1.3 src/sys/external/bsd/drm2/include/linux/refcount.h
cvs rdiff -u -r1.13 -r1.14 src/sys/external/bsd/drm2/include/linux/spinlock.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_active.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_active.c:1.3 src/sys/external/bsd/drm2/dist/drm/i915/i915_active.c:1.4
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_active.c:1.3	Sun Dec 19 01:44:57 2021
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_active.c	Sun Dec 19 11:52:07 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: i915_active.c,v 1.3 2021/12/19 01:44:57 riastradh Exp $	*/
+/*	$NetBSD: i915_active.c,v 1.4 2021/12/19 11:52:07 riastradh Exp $	*/
 
 /*
  * SPDX-License-Identifier: MIT
@@ -7,7 +7,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i915_active.c,v 1.3 2021/12/19 01:44:57 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i915_active.c,v 1.4 2021/12/19 11:52:07 riastradh Exp $");
 
 #include <linux/debugobjects.h>
 
@@ -19,6 +19,8 @@ __KERNEL_RCSID(0, "$NetBSD: i915_active.
 #include "i915_active.h"
 #include "i915_globals.h"
 
+#include <linux/nbsd-namespace.h>
+
 /*
  * Active refs memory management
  *
@@ -36,6 +38,7 @@ struct active_node {
 	struct i915_active *ref;
 	struct rb_node node;
 	u64 timeline;
+	struct intel_engine_cs *engine;
 };
 
 static inline struct active_node *
@@ -54,13 +57,13 @@ static inline bool is_barrier(const stru
 static inline struct llist_node *barrier_to_ll(struct active_node *node)
 {
 	GEM_BUG_ON(!is_barrier(&node->base));
-	return (struct llist_node *)&node->base.cb.node;
+	return &node->base.llist;
 }
 
 static inline struct intel_engine_cs *
 __barrier_to_engine(struct active_node *node)
 {
-	return (struct intel_engine_cs *)READ_ONCE(node->base.cb.node.prev);
+	return READ_ONCE(node->engine);
 }
 
 static inline struct intel_engine_cs *
@@ -72,8 +75,7 @@ barrier_to_engine(struct active_node *no
 
 static inline struct active_node *barrier_from_ll(struct llist_node *x)
 {
-	return container_of((struct list_head *)x,
-			    struct active_node, base.cb.node);
+	return container_of(x, struct active_node, base.llist);
 }
 
 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) && IS_ENABLED(CONFIG_DEBUG_OBJECTS)
@@ -129,6 +131,42 @@ static inline void debug_active_assert(s
 
 #endif
 
+#ifdef __NetBSD__
+
+static int
+compare_nodes(void *cookie, const void *va, const void *vb)
+{
+	const struct active_node *a = va;
+	const struct active_node *b = vb;
+
+	if (a->timeline < b->timeline)
+		return -1;
+	if (a->timeline > b->timeline)
+		return +1;
+	return 0;
+}
+
+static int
+compare_node_key(void *cookie, const void *vn, const void *vk)
+{
+	const struct active_node *a = vn;
+	const uint64_t *k = vk;
+
+	if (a->timeline < *k)
+		return -1;
+	if (a->timeline > *k)
+		return +1;
+	return 0;
+}
+
+static const rb_tree_ops_t active_rb_ops = {
+	.rbto_compare_nodes = compare_nodes,
+	.rbto_compare_key = compare_node_key,
+	.rbto_node_offset = offsetof(struct active_node, node),
+};
+
+#endif
+
 static void
 __active_retire(struct i915_active *ref)
 {
@@ -146,9 +184,15 @@ __active_retire(struct i915_active *ref)
 	debug_active_deactivate(ref);
 
 	root = ref->tree;
+#ifdef __NetBSD__
+	rb_tree_init(&ref->tree.rbr_tree, &active_rb_ops);
+#else
 	ref->tree = RB_ROOT;
+#endif
 	ref->cache = NULL;
 
+	DRM_SPIN_WAKEUP_ALL(&ref->tree_wq, &ref->tree_lock);
+
 	spin_unlock_irqrestore(&ref->tree_lock, flags);
 
 	/* After the final retire, the entire struct may be freed */
@@ -156,7 +200,6 @@ __active_retire(struct i915_active *ref)
 		ref->retire(ref);
 
 	/* ... except if you wait on it, you must manage your own references! */
-	wake_up_var(ref);
 
 	rbtree_postorder_for_each_entry_safe(it, n, &root, node) {
 		GEM_BUG_ON(i915_active_fence_isset(&it->base));
@@ -249,7 +292,7 @@ active_instance(struct i915_active *ref,
 #ifdef __NetBSD__
 	__USE(parent);
 	__USE(p);
-	node = rb_tree_find_node(&vma->active.rbr_tree, &idx);
+	node = rb_tree_find_node(&ref->tree.rbr_tree, &idx);
 	if (node) {
 		KASSERT(node->timeline == idx);
 		goto out;
@@ -279,8 +322,8 @@ active_instance(struct i915_active *ref,
 	node->timeline = idx;
 
 #ifdef __NetBSD__
-	struct i915_vma_active *collision __diagused;
-	collision = rb_tree_insert_node(&vma->active.rbr_tree, node);
+	struct active_node *collision __diagused;
+	collision = rb_tree_insert_node(&ref->tree.rbr_tree, node);
 	KASSERT(collision == node);
 #else
 	rb_link_node(&node->node, parent, p);
@@ -295,40 +338,6 @@ out:
 	return &node->base;
 }
 
-#ifdef __NetBSD__
-static int
-compare_active(void *cookie, const void *va, const void *vb)
-{
-	const struct i915_active *a = va;
-	const struct i915_active *b = vb;
-
-	if (a->timeline < b->timeline)
-		return -1;
-	if (a->timeline > b->timeline)
-		return +1;
-	return 0;
-}
-
-static int
-compare_active_key(void *cookie, const void *vn, const void *vk)
-{
-	const struct i915_active *a = vn;
-	const uint64_t *k = vk;
-
-	if (a->timeline < *k)
-		return -1;
-	if (a->timeline > *k)
-		return +1;
-	return 0;
-}
-
-static const rb_tree_ops_t active_rb_ops = {
-	.rbto_compare_nodes = compare_active,
-	.rbto_compare_key = compare_active_key,
-	.rbto_node_offset = offsetof(struct i915_active, node),
-};
-#endif
-
 void __i915_active_init(struct i915_active *ref,
 			int (*active)(struct i915_active *ref),
 			void (*retire)(struct i915_active *ref),
@@ -346,8 +355,9 @@ void __i915_active_init(struct i915_acti
 		ref->flags |= I915_ACTIVE_RETIRE_SLEEPS;
 
 	spin_lock_init(&ref->tree_lock);
+	DRM_INIT_WAITQUEUE(&ref->tree_wq, "i915act");
 #ifdef __NetBSD__
-	rb_tree_init(&vma->active.rbr_tree, &active_rb_ops);
+	rb_tree_init(&ref->tree.rbr_tree, &active_rb_ops);
 #else
 	ref->tree = RB_ROOT;
 #endif
@@ -533,8 +543,12 @@ int i915_active_wait(struct i915_active 
 	if (err)
 		return err;
 
-	if (wait_var_event_interruptible(ref, i915_active_is_idle(ref)))
-		return -EINTR;
+	spin_lock(&ref->tree_lock);
+	DRM_SPIN_WAIT_UNTIL(err, &ref->tree_wq, &ref->tree_lock,
+	    i915_active_is_idle(ref));
+	spin_unlock(&ref->tree_lock);
+	if (err)
+		return err;
 
 	flush_work(&ref->work);
 	return 0;
@@ -599,6 +613,21 @@ static struct active_node *reuse_idle_ba
 		goto match;
 	}
 
+#ifdef __NetBSD__
+    {
+	struct active_node *node =
+	    rb_tree_find_node_leq(&ref->tree.rbr_tree, &idx);
+	if (node) {
+		if (node->timeline == idx && is_idle_barrier(node, idx)) {
+			p = &node->node;
+			goto match;
+		}
+		prev = &node->node;
+	} else {
+		prev = NULL;
+	}
+    }
+#else
 	prev = NULL;
 	p = ref->tree.rb_node;
 	while (p) {
@@ -614,6 +643,7 @@ static struct active_node *reuse_idle_ba
 		else
 			p = p->rb_left;
 	}
+#endif
 
 	/*
 	 * No quick match, but we did find the leftmost rb_node for the
@@ -621,7 +651,7 @@ static struct active_node *reuse_idle_ba
 	 * any idle-barriers on this timeline that we missed, or just use
 	 * the first pending barrier.
 	 */
-	for (p = prev; p; p = rb_next(p)) {
+	for (p = prev; p; p = rb_next2(&ref->tree, p)) {
 		struct active_node *node =
 			rb_entry(p, struct active_node, node);
 		struct intel_engine_cs *engine;
@@ -712,7 +742,7 @@ int i915_active_acquire_preallocate_barr
 			 * for our tracking of the pending barrier.
 			 */
 			RCU_INIT_POINTER(node->base.fence, ERR_PTR(-EAGAIN));
-			node->base.cb.node.prev = (void *)engine;
+			node->engine = engine;
 			atomic_inc(&ref->count);
 		}
 		GEM_BUG_ON(rcu_access_pointer(node->base.fence) != ERR_PTR(-EAGAIN));
@@ -764,6 +794,13 @@ void i915_active_acquire_barrier(struct 
 
 		spin_lock_irqsave_nested(&ref->tree_lock, flags,
 					 SINGLE_DEPTH_NESTING);
+#ifdef __NetBSD__
+		__USE(p);
+		__USE(parent);
+		struct active_node *collision __diagused;
+		collision = rb_tree_insert_node(&ref->tree.rbr_tree, node);
+		KASSERT(collision == node);
+#else
 		parent = NULL;
 		p = &ref->tree.rb_node;
 		while (*p) {
@@ -779,6 +816,7 @@ void i915_active_acquire_barrier(struct 
 		}
 		rb_link_node(&node->node, parent, p);
 		rb_insert_color(&node->node, &ref->tree);
+#endif
 		spin_unlock_irqrestore(&ref->tree_lock, flags);
 
 		GEM_BUG_ON(!intel_engine_pm_is_awake(engine));
@@ -814,7 +852,18 @@ void i915_request_add_active_barriers(st
 	llist_for_each_safe(node, next, node) {
 		/* serialise with reuse_idle_barrier */
 		smp_store_mb(*ll_to_fence_slot(node), &rq->fence);
+#ifdef __NetBSD__
+		spin_unlock(&rq->lock);
+		struct i915_active_fence *fence =
+		    container_of(node, struct i915_active_fence, llist);
+		/* XXX something bad went wrong in making this code */
+		KASSERT(fence->cb.func == node_retire);
+		(void)dma_fence_add_callback(fence->fence, &fence->cb,
+		    node_retire);
+		spin_lock(&rq->lock);
+#else
 		list_add_tail((struct list_head *)node, &rq->fence.cb_list);
+#endif
 	}
 	spin_unlock_irqrestore(&rq->lock, flags);
 }
@@ -867,14 +916,26 @@ __i915_active_fence_set(struct i915_acti
 	prev = xchg(__active_fence_slot(active), fence);
 	if (prev) {
 		GEM_BUG_ON(prev == fence);
+#ifdef __NetBSD__
+		KASSERT(active->cb.func == node_retire);
+		(void)dma_fence_remove_callback(prev, &active->cb);
+#else
 		spin_lock_nested(prev->lock, SINGLE_DEPTH_NESTING);
 		__list_del_entry(&active->cb.node);
 		spin_unlock(prev->lock); /* serialise with prev->cb_list */
+#endif
 	}
 	GEM_BUG_ON(rcu_access_pointer(active->fence) != fence);
+#ifndef __NetBSD__
 	list_add_tail(&active->cb.node, &fence->cb_list);
+#endif
 	spin_unlock_irqrestore(fence->lock, flags);
 
+#ifdef __NetBSD__
+	KASSERT(active->cb.func == node_retire);
+	dma_fence_add_callback(fence, &active->cb, node_retire);
+#endif
+
 	return prev;
 }
 

Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_active_types.h
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_active_types.h:1.2 src/sys/external/bsd/drm2/dist/drm/i915/i915_active_types.h:1.3
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_active_types.h:1.2	Sat Dec 18 23:45:28 2021
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_active_types.h	Sun Dec 19 11:52:07 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: i915_active_types.h,v 1.2 2021/12/18 23:45:28 riastradh Exp $	*/
+/*	$NetBSD: i915_active_types.h,v 1.3 2021/12/19 11:52:07 riastradh Exp $	*/
 
 /*
  * SPDX-License-Identifier: MIT
@@ -17,11 +17,14 @@
 #include <linux/rcupdate.h>
 #include <linux/workqueue.h>
 
+#include <drm/drm_wait_netbsd.h> /* XXX */
+
 #include "i915_utils.h"
 
 struct i915_active_fence {
 	struct dma_fence __rcu *fence;
 	struct dma_fence_cb cb;
+	struct llist_node llist;
 };
 
 struct active_node;
@@ -36,6 +39,7 @@ struct i915_active {
 	struct mutex mutex;
 
 	spinlock_t tree_lock;
+	drm_waitqueue_t tree_wq;
 	struct active_node *cache;
 	struct rb_root tree;
 

Index: src/sys/external/bsd/drm2/dist/drm/i915/gt/intel_engine_pm.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/gt/intel_engine_pm.c:1.2 src/sys/external/bsd/drm2/dist/drm/i915/gt/intel_engine_pm.c:1.3
--- src/sys/external/bsd/drm2/dist/drm/i915/gt/intel_engine_pm.c:1.2	Sat Dec 18 23:45:30 2021
+++ src/sys/external/bsd/drm2/dist/drm/i915/gt/intel_engine_pm.c	Sun Dec 19 11:52:07 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: intel_engine_pm.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $	*/
+/*	$NetBSD: intel_engine_pm.c,v 1.3 2021/12/19 11:52:07 riastradh Exp $	*/
 
 /*
  * SPDX-License-Identifier: MIT
@@ -7,7 +7,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intel_engine_pm.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intel_engine_pm.c,v 1.3 2021/12/19 11:52:07 riastradh Exp $");
 
 #include "i915_drv.h"
 
@@ -229,11 +229,10 @@ static void call_idle_barriers(struct in
 	struct llist_node *node, *next;
 
 	llist_for_each_safe(node, next, llist_del_all(&engine->barrier_tasks)) {
-		struct dma_fence_cb *cb =
-			container_of((struct list_head *)node,
-				     typeof(*cb), node);
+		struct i915_active_fence *fence =
+		    container_of(node, struct i915_active_fence, llist);
 
-		cb->func(ERR_PTR(-EAGAIN), cb);
+		fence->cb.func(ERR_PTR(-EAGAIN), &fence->cb);
 	}
 }
 

Index: src/sys/external/bsd/drm2/i915drm/files.i915drmkms
diff -u src/sys/external/bsd/drm2/i915drm/files.i915drmkms:1.82 src/sys/external/bsd/drm2/i915drm/files.i915drmkms:1.83
--- src/sys/external/bsd/drm2/i915drm/files.i915drmkms:1.82	Sun Dec 19 11:51:59 2021
+++ src/sys/external/bsd/drm2/i915drm/files.i915drmkms	Sun Dec 19 11:52:07 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: files.i915drmkms,v 1.82 2021/12/19 11:51:59 riastradh Exp $
+#	$NetBSD: files.i915drmkms,v 1.83 2021/12/19 11:52:07 riastradh Exp $
 
 version	20180827
 
@@ -169,7 +169,7 @@ file	external/bsd/drm2/dist/drm/i915/gt/
 file	external/bsd/drm2/dist/drm/i915/gt/intel_context.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/gt/intel_engine_cs.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/gt/intel_engine_heartbeat.c	i915drmkms
-#file	external/bsd/drm2/dist/drm/i915/gt/intel_engine_pm.c	i915drmkms
+file	external/bsd/drm2/dist/drm/i915/gt/intel_engine_pm.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/gt/intel_engine_pool.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/gt/intel_engine_user.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/gt/intel_ggtt.c	i915drmkms
@@ -202,7 +202,7 @@ file	external/bsd/drm2/dist/drm/i915/gt/
 file	external/bsd/drm2/dist/drm/i915/gt/uc/intel_huc_fw.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/gt/uc/intel_uc.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/gt/uc/intel_uc_fw.c	i915drmkms
-#file	external/bsd/drm2/dist/drm/i915/i915_active.c	i915drmkms
+file	external/bsd/drm2/dist/drm/i915/i915_active.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/i915_buddy.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/i915_cmd_parser.c	i915drmkms
 file	external/bsd/drm2/dist/drm/i915/i915_drv.c	i915drmkms

Index: src/sys/external/bsd/drm2/include/linux/llist.h
diff -u src/sys/external/bsd/drm2/include/linux/llist.h:1.5 src/sys/external/bsd/drm2/include/linux/llist.h:1.6
--- src/sys/external/bsd/drm2/include/linux/llist.h:1.5	Sun Dec 19 11:39:24 2021
+++ src/sys/external/bsd/drm2/include/linux/llist.h	Sun Dec 19 11:52:08 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: llist.h,v 1.5 2021/12/19 11:39:24 riastradh Exp $	*/
+/*	$NetBSD: llist.h,v 1.6 2021/12/19 11:52:08 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -76,6 +76,20 @@ llist_add(struct llist_node *node, struc
 	return first == NULL;
 }
 
+static inline bool
+llist_add_batch(struct llist_node *first, struct llist_node *last,
+    struct llist_head *head)
+{
+	struct llist_node *next;
+
+	do {
+		next = atomic_load_consume(&head->first);
+		last->next = next;
+	} while (atomic_cas_ptr(&head->first, next, first) != next);
+
+	return next == NULL;
+}
+
 static inline struct llist_node *
 llist_del_all(struct llist_head *head)
 {

Index: src/sys/external/bsd/drm2/include/linux/refcount.h
diff -u src/sys/external/bsd/drm2/include/linux/refcount.h:1.2 src/sys/external/bsd/drm2/include/linux/refcount.h:1.3
--- src/sys/external/bsd/drm2/include/linux/refcount.h:1.2	Sun Dec 19 10:48:37 2021
+++ src/sys/external/bsd/drm2/include/linux/refcount.h	Sun Dec 19 11:52:08 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: refcount.h,v 1.2 2021/12/19 10:48:37 riastradh Exp $	*/
+/*	$NetBSD: refcount.h,v 1.3 2021/12/19 11:52:08 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -84,24 +84,8 @@ static inline bool __must_check
 refcount_dec_and_lock_irqsave(struct refcount *rc, struct spinlock *lock,
     unsigned long *flagsp)
 {
-	unsigned old, new;
 
-	do {
-		old = atomic_read(&rc->rc_count);
-		KASSERT(old);
-		if (old == 1) {
-			spin_lock_irqsave(lock, *flagsp);
-			if (atomic_dec_return(&rc->rc_count) == 0)
-				return true;
-			spin_unlock_irqrestore(lock, *flagsp);
-			return false;
-		}
-		new = old - 1;
-	} while (atomic_cmpxchg(&rc->rc_count, old, new) != old);
-
-	KASSERT(old != 1);
-	KASSERT(new != 0);
-	return false;
+	return atomic_dec_and_lock_irqsave(&rc->rc_count, lock, *flagsp);
 }
 
 static inline bool __must_check

Index: src/sys/external/bsd/drm2/include/linux/spinlock.h
diff -u src/sys/external/bsd/drm2/include/linux/spinlock.h:1.13 src/sys/external/bsd/drm2/include/linux/spinlock.h:1.14
--- src/sys/external/bsd/drm2/include/linux/spinlock.h:1.13	Sun Dec 19 11:47:55 2021
+++ src/sys/external/bsd/drm2/include/linux/spinlock.h	Sun Dec 19 11:52:08 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: spinlock.h,v 1.13 2021/12/19 11:47:55 riastradh Exp $	*/
+/*	$NetBSD: spinlock.h,v 1.14 2021/12/19 11:52:08 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -37,6 +37,7 @@
 
 #include <machine/limits.h>
 
+#include <linux/atomic.h>
 #include <linux/irqflags.h>
 #include <linux/lockdep.h>
 #include <linux/preempt.h>
@@ -201,4 +202,31 @@ local_bh_enable(void)
 {
 }
 
+#define	atomic_dec_and_lock_irqsave(A, L, F)				      \
+	_atomic_dec_and_lock_irqsave(A, L, &(F))
+
+static inline bool __must_check
+_atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
+    unsigned long *flagsp)
+{
+	unsigned old, new;
+
+	do {
+		old = atomic_read(atomic);
+		KASSERT(old);
+		if (old == 1) {
+			spin_lock_irqsave(lock, *flagsp);
+			if (atomic_dec_return(atomic) == 0)
+				return true;
+			spin_unlock_irqrestore(lock, *flagsp);
+			return false;
+		}
+		new = old - 1;
+	} while (atomic_cmpxchg(atomic, old, new) != old);
+
+	KASSERT(old != 1);
+	KASSERT(new != 0);
+	return false;
+}
+
 #endif  /* _LINUX_SPINLOCK_H_ */

Reply via email to