1 /* $NetBSD: drm_wait_netbsd.h,v 1.4 2014/07/16 20:59:58 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Taylor R. Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef _DRM_DRM_WAIT_NETBSD_H_ 33 #define _DRM_DRM_WAIT_NETBSD_H_ 34 35 #include <sys/param.h> 36 #include <sys/condvar.h> 37 #if DIAGNOSTIC 38 #include <sys/cpu.h> /* cpu_intr_p */ 39 #endif 40 #include <sys/kernel.h> 41 #include <sys/mutex.h> 42 #include <sys/systm.h> 43 44 #include <linux/mutex.h> 45 #include <linux/spinlock.h> 46 47 typedef kcondvar_t drm_waitqueue_t; 48 49 #define DRM_HZ hz /* XXX Hurk... */ 50 51 #define DRM_UDELAY DELAY 52 53 static inline void 54 DRM_INIT_WAITQUEUE(drm_waitqueue_t *q, const char *name) 55 { 56 cv_init(q, name); 57 } 58 59 static inline void 60 DRM_DESTROY_WAITQUEUE(drm_waitqueue_t *q) 61 { 62 cv_destroy(q); 63 } 64 65 static inline bool 66 DRM_WAITERS_P(drm_waitqueue_t *q, struct mutex *interlock) 67 { 68 KASSERT(mutex_is_locked(interlock)); 69 return cv_has_waiters(q); 70 } 71 72 static inline void 73 DRM_WAKEUP_ONE(drm_waitqueue_t *q, struct mutex *interlock) 74 { 75 KASSERT(mutex_is_locked(interlock)); 76 cv_signal(q); 77 } 78 79 static inline void 80 DRM_WAKEUP_ALL(drm_waitqueue_t *q, struct mutex *interlock) 81 { 82 KASSERT(mutex_is_locked(interlock)); 83 cv_broadcast(q); 84 } 85 86 static inline bool 87 DRM_SPIN_WAITERS_P(drm_waitqueue_t *q, spinlock_t *interlock) 88 { 89 KASSERT(spin_is_locked(interlock)); 90 return cv_has_waiters(q); 91 } 92 93 static inline void 94 DRM_SPIN_WAKEUP_ONE(drm_waitqueue_t *q, spinlock_t *interlock) 95 { 96 KASSERT(spin_is_locked(interlock)); 97 cv_signal(q); 98 } 99 100 static inline void 101 DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, spinlock_t *interlock) 102 { 103 KASSERT(spin_is_locked(interlock)); 104 cv_broadcast(q); 105 } 106 107 #define _DRM_WAIT_UNTIL(RET, WAIT, Q, INTERLOCK, CONDITION) do \ 108 { \ 109 KASSERT(mutex_is_locked((INTERLOCK))); \ 110 ASSERT_SLEEPABLE(); \ 111 KASSERT(!cold); \ 112 for (;;) { \ 113 if (CONDITION) { \ 114 (RET) = 0; \ 115 break; \ 116 } \ 117 /* XXX errno NetBSD->Linux */ \ 118 (RET) = -WAIT((Q), &(INTERLOCK)->mtx_lock); \ 119 if (RET) \ 120 break; \ 121 } \ 122 } while (0) 123 124 #define cv_wait_nointr(Q, I) (cv_wait((Q), (I)), 0) 125 126 #define DRM_WAIT_NOINTR_UNTIL(RET, Q, I, C) \ 127 _DRM_WAIT_UNTIL(RET, cv_wait_nointr, Q, I, C) 128 129 #define DRM_WAIT_UNTIL(RET, Q, I, C) \ 130 _DRM_WAIT_UNTIL(RET, cv_wait_sig, Q, I, C) 131 132 #define _DRM_TIMED_WAIT_UNTIL(RET, WAIT, Q, INTERLOCK, TICKS, CONDITION) do \ 133 { \ 134 extern int hardclock_ticks; \ 135 const int _dtwu_start = hardclock_ticks; \ 136 int _dtwu_ticks = (TICKS); \ 137 KASSERT(mutex_is_locked((INTERLOCK))); \ 138 ASSERT_SLEEPABLE(); \ 139 KASSERT(!cold); \ 140 for (;;) { \ 141 if (CONDITION) { \ 142 (RET) = _dtwu_ticks; \ 143 break; \ 144 } \ 145 /* XXX errno NetBSD->Linux */ \ 146 (RET) = -WAIT((Q), &(INTERLOCK)->mtx_lock, \ 147 _dtwu_ticks); \ 148 if (RET) \ 149 break; \ 150 const int _dtwu_now = hardclock_ticks; \ 151 KASSERT(_dtwu_start <= _dtwu_now); \ 152 if ((_dtwu_now - _dtwu_start) < _dtwu_ticks) { \ 153 _dtwu_ticks -= (_dtwu_now - _dtwu_start); \ 154 } else { \ 155 (RET) = 0; \ 156 break; \ 157 } \ 158 } \ 159 } while (0) 160 161 #define DRM_TIMED_WAIT_NOINTR_UNTIL(RET, Q, I, T, C) \ 162 _DRM_TIMED_WAIT_UNTIL(RET, cv_timedwait, Q, I, T, C) 163 164 #define DRM_TIMED_WAIT_UNTIL(RET, Q, I, T, C) \ 165 _DRM_TIMED_WAIT_UNTIL(RET, cv_timedwait_sig, Q, I, T, C) 166 167 /* 168 * XXX Can't assert sleepable here because we hold a spin lock. At 169 * least we can assert that we're not in (soft) interrupt context, and 170 * hope that nobody tries to use these with a sometimes quickly 171 * satisfied condition while holding a different spin lock. 172 */ 173 174 #define _DRM_SPIN_WAIT_UNTIL(RET, WAIT, Q, INTERLOCK, CONDITION) do \ 175 { \ 176 KASSERT(spin_is_locked((INTERLOCK))); \ 177 KASSERT(!cpu_intr_p()); \ 178 KASSERT(!cpu_softintr_p()); \ 179 KASSERT(!cold); \ 180 while (!(CONDITION)) { \ 181 /* XXX errno NetBSD->Linux */ \ 182 (RET) = -WAIT((Q), &(INTERLOCK)->sl_lock); \ 183 if (RET) \ 184 break; \ 185 } \ 186 } while (0) 187 188 #define DRM_SPIN_WAIT_NOINTR_UNTIL(RET, Q, I, C) \ 189 _DRM_SPIN_WAIT_UNTIL(RET, cv_wait_nointr, Q, I, C) 190 191 #define DRM_SPIN_WAIT_UNTIL(RET, Q, I, C) \ 192 _DRM_SPIN_WAIT_UNTIL(RET, cv_wait_sig, Q, I, C) 193 194 #define _DRM_SPIN_TIMED_WAIT_UNTIL(RET, WAIT, Q, INTERLOCK, TICKS, CONDITION) \ 195 do \ 196 { \ 197 extern int hardclock_ticks; \ 198 const int _dstwu_start = hardclock_ticks; \ 199 int _dstwu_ticks = (TICKS); \ 200 KASSERT(spin_is_locked((INTERLOCK))); \ 201 KASSERT(!cpu_intr_p()); \ 202 KASSERT(!cpu_softintr_p()); \ 203 KASSERT(!cold); \ 204 for (;;) { \ 205 if (CONDITION) { \ 206 (RET) = _dstwu_ticks; \ 207 break; \ 208 } \ 209 /* XXX errno NetBSD->Linux */ \ 210 (RET) = -WAIT((Q), &(INTERLOCK)->sl_lock, \ 211 _dstwu_ticks); \ 212 if (RET) \ 213 break; \ 214 const int _dstwu_now = hardclock_ticks; \ 215 KASSERT(_dstwu_start <= _dstwu_now); \ 216 if ((_dstwu_now - _dstwu_start) < _dstwu_ticks) { \ 217 _dstwu_ticks -= (_dstwu_now - _dstwu_start); \ 218 } else { \ 219 (RET) = 0; \ 220 break; \ 221 } \ 222 } \ 223 } while (0) 224 225 #define DRM_SPIN_TIMED_WAIT_NOINTR_UNTIL(RET, Q, I, T, C) \ 226 _DRM_SPIN_TIMED_WAIT_UNTIL(RET, cv_timedwait, Q, I, T, C) 227 228 #define DRM_SPIN_TIMED_WAIT_UNTIL(RET, Q, I, T, C) \ 229 _DRM_SPIN_TIMED_WAIT_UNTIL(RET, cv_timedwait_sig, Q, I, T, C) 230 231 #endif /* _DRM_DRM_WAIT_NETBSD_H_ */ 232