aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linuxkpi/common
diff options
context:
space:
mode:
authorVladimir Kondratyev <wulf@FreeBSD.org>2022-01-18 20:14:12 +0000
committerVladimir Kondratyev <wulf@FreeBSD.org>2022-01-18 20:14:12 +0000
commit02ea6033020e11afec6472bf560b0ddebd0fa97a (patch)
tree27ab11801c79a2426941ae695ec9bff8cfe06c10 /sys/compat/linuxkpi/common
parenta50e92cc203c1e3dd2cca03410b568f76694895c (diff)
downloadsrc-02ea6033020e11afec6472bf560b0ddebd0fa97a.tar.gz
src-02ea6033020e11afec6472bf560b0ddebd0fa97a.zip
LinuxKPI: Allow spin_lock_irqsave to be called within a critical section
with spinning on spin_trylock. dma-buf part of drm-kmod depends on this property and absence of it support results in "mi_switch: switch in a critical section" assertions [1][2]. [1] https://github.com/freebsd/drm-kmod/issues/116 [2] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=261166 MFC after: 1 week Reviewed by: manu Differential Revision: https://reviews.freebsd.org/D33887
Diffstat (limited to 'sys/compat/linuxkpi/common')
-rw-r--r--sys/compat/linuxkpi/common/include/linux/spinlock.h27
1 files changed, 23 insertions, 4 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h
index a87cb7180b28..31d47fa73986 100644
--- a/sys/compat/linuxkpi/common/include/linux/spinlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h
@@ -37,6 +37,7 @@
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/kdb.h>
+#include <sys/proc.h>
#include <linux/compiler.h>
#include <linux/rwlock.h>
@@ -117,14 +118,32 @@ typedef struct {
local_bh_disable(); \
} while (0)
-#define spin_lock_irqsave(_l, flags) do { \
- (flags) = 0; \
- spin_lock(_l); \
+#define __spin_trylock_nested(_l, _n) ({ \
+ int __ret; \
+ if (SPIN_SKIP()) { \
+ __ret = 1; \
+ } else { \
+ __ret = mtx_trylock_flags(&(_l)->m, MTX_DUPOK); \
+ if (likely(__ret != 0)) \
+ local_bh_disable(); \
+ } \
+ __ret; \
+})
+
+#define spin_lock_irqsave(_l, flags) do { \
+ (flags) = 0; \
+ if (unlikely(curthread->td_critnest != 0)) \
+ while (!spin_trylock(_l)) {} \
+ else \
+ spin_lock(_l); \
} while (0)
#define spin_lock_irqsave_nested(_l, flags, _n) do { \
(flags) = 0; \
- spin_lock_nested(_l, _n); \
+ if (unlikely(curthread->td_critnest != 0)) \
+ while (!__spin_trylock_nested(_l, _n)) {} \
+ else \
+ spin_lock_nested(_l, _n); \
} while (0)
#define spin_unlock_irqrestore(_l, flags) do { \