1 /*- 2 * Copyright (c) 2010 Max Khon <fjoe@freebsd.org> 3 * All rights reserved. 4 * 5 * This software was developed by Max Khon under sponsorship from 6 * the FreeBSD Foundation and Ethon Technologies GmbH. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Id: vchi_bsd.c,v 1.10 2017/11/05 09:11:43 skrll Exp $ 30 */ 31 32 #include <sys/types.h> 33 #include <sys/bus.h> 34 #include <sys/callout.h> 35 #include <sys/param.h> 36 #include <sys/proc.h> 37 #include <sys/systm.h> 38 39 #include <interface/compat/vchi_bsd.h> 40 41 MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI"); 42 43 /* 44 * Timer API 45 */ 46 static void 47 run_timer(void *arg) 48 { 49 struct timer_list *t = (struct timer_list *) arg; 50 void (*function)(unsigned long); 51 52 spin_lock(&t->mtx); 53 if (callout_pending(&t->callout)) { 54 /* callout was reset */ 55 spin_unlock(&t->mtx); 56 return; 57 } 58 if (!callout_active(&t->callout)) { 59 /* callout was stopped */ 60 spin_unlock(&t->mtx); 61 return; 62 } 63 callout_ack(&t->callout); 64 65 function = t->function; 66 spin_unlock(&t->mtx); 67 68 function(t->data); 69 } 70 71 void 72 init_timer(struct timer_list *t) 73 { 74 spin_lock_init(&t->mtx); 75 callout_init(&t->callout, CALLOUT_MPSAFE); 76 t->expires = 0; 77 /* 78 * function and data are not initialized intentionally: 79 * they are not initialized by Linux implementation too 80 */ 81 } 82 83 void 84 setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data) 85 { 86 t->function = function; 87 t->data = data; 88 init_timer(t); 89 } 90 91 void 92 mod_timer(struct timer_list *t, unsigned long expires) 93 { 94 spin_lock(&t->mtx); 95 callout_reset(&t->callout, expires - jiffies, run_timer, t); 96 spin_unlock(&t->mtx); 97 } 98 99 void 100 add_timer(struct timer_list *t) 101 { 102 mod_timer(t, t->expires); 103 } 104 105 int 106 del_timer_sync(struct timer_list *t) 107 { 108 spin_lock(&t->mtx); 109 callout_halt(&t->callout, &t->mtx); 110 spin_unlock(&t->mtx); 111 112 spin_lock_destroy(&t->mtx); 113 return 0; 114 } 115 116 int 117 del_timer(struct timer_list *t) 118 { 119 del_timer_sync(t); 120 return 0; 121 } 122 123 /* 124 * Semaphore API 125 */ 126 127 void sema_sysinit(void *arg) 128 { 129 struct semaphore *s = arg; 130 131 printf("sema_sysinit\n"); 132 _sema_init(s, 1); 133 } 134 135 void 136 _sema_init(struct semaphore *s, int value) 137 { 138 memset(s, 0, sizeof(*s)); 139 mutex_init(&s->mtx, MUTEX_DEFAULT, IPL_VM); 140 cv_init(&s->cv, "semacv"); 141 s->value = value; 142 } 143 144 void 145 _sema_destroy(struct semaphore *s) 146 { 147 mutex_destroy(&s->mtx); 148 cv_destroy(&s->cv); 149 } 150 151 void 152 down(struct semaphore *s) 153 { 154 155 mutex_enter(&s->mtx); 156 while (s->value == 0) { 157 s->waiters++; 158 cv_wait(&s->cv, &s->mtx); 159 s->waiters--; 160 } 161 162 s->value--; 163 mutex_exit(&s->mtx); 164 } 165 166 int 167 down_interruptible(struct semaphore *s) 168 { 169 170 mutex_enter(&s->mtx); 171 172 while (s->value == 0) { 173 s->waiters++; 174 int ret = cv_wait_sig(&s->cv, &s->mtx); 175 s->waiters--; 176 177 if (ret == EINTR || ret == ERESTART) { 178 mutex_exit(&s->mtx); 179 return -EINTR; 180 } 181 } 182 183 s->value--; 184 mutex_exit(&s->mtx); 185 186 return 0; 187 } 188 189 int 190 down_trylock(struct semaphore *s) 191 { 192 int ret = 1; 193 194 mutex_enter(&s->mtx); 195 196 if (s->value > 0) { 197 /* Success. */ 198 s->value--; 199 ret = 0; 200 } 201 202 mutex_exit(&s->mtx); 203 204 return ret; 205 } 206 207 void 208 up(struct semaphore *s) 209 { 210 mutex_enter(&s->mtx); 211 s->value++; 212 if (s->value > 0 && s->waiters) 213 cv_signal(&s->cv); 214 215 mutex_exit(&s->mtx); 216 } 217 218 /* 219 * Logging API 220 */ 221 void 222 rlprintf(int pps, const char *fmt, ...) 223 { 224 va_list ap; 225 static struct timeval last_printf; 226 static int count; 227 228 if (ppsratecheck(&last_printf, &count, pps)) { 229 va_start(ap, fmt); 230 vprintf(fmt, ap); 231 va_end(ap); 232 } 233 } 234 235 void 236 device_rlprintf(int pps, device_t dev, const char *fmt, ...) 237 { 238 va_list ap; 239 static struct timeval last_printf; 240 static int count; 241 242 if (ppsratecheck(&last_printf, &count, pps)) { 243 va_start(ap, fmt); 244 device_print_prettyname(dev); 245 vprintf(fmt, ap); 246 va_end(ap); 247 } 248 } 249 250 /* 251 * Signals API 252 */ 253 254 void 255 flush_signals(VCHIQ_THREAD_T thr) 256 { 257 printf("Implement ME: %s\n", __func__); 258 } 259 260 int 261 fatal_signal_pending(VCHIQ_THREAD_T thr) 262 { 263 printf("Implement ME: %s\n", __func__); 264 return 0; 265 } 266 267 /* 268 * kthread API 269 */ 270 271 /* 272 * This is a hack to avoid memory leak 273 */ 274 #define MAX_THREAD_DATA_SLOTS 32 275 static int thread_data_slot = 0; 276 277 struct thread_data { 278 void *data; 279 int (*threadfn)(void *); 280 }; 281 282 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS]; 283 284 static void 285 kthread_wrapper(void *data) 286 { 287 struct thread_data *slot; 288 289 slot = data; 290 slot->threadfn(slot->data); 291 } 292 293 VCHIQ_THREAD_T 294 vchiq_thread_create(int (*threadfn)(void *data), 295 void *data, 296 const char namefmt[], ...) 297 { 298 VCHIQ_THREAD_T newt; 299 va_list ap; 300 char name[MAXCOMLEN+1]; 301 struct thread_data *slot; 302 303 if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) { 304 printf("kthread_create: out of thread data slots\n"); 305 return NULL; 306 } 307 308 slot = &thread_slots[thread_data_slot]; 309 slot->data = data; 310 slot->threadfn = threadfn; 311 312 va_start(ap, namefmt); 313 vsnprintf(name, sizeof(name), namefmt, ap); 314 va_end(ap); 315 316 newt = NULL; 317 if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, kthread_wrapper, 318 slot, &newt, "%s", name) != 0) { 319 /* Just to be sure */ 320 newt = NULL; 321 } else { 322 thread_data_slot++; 323 } 324 325 return newt; 326 } 327 328 void 329 set_user_nice(VCHIQ_THREAD_T thr, int nice) 330 { 331 /* NOOP */ 332 } 333 334 void 335 wake_up_process(VCHIQ_THREAD_T thr) 336 { 337 /* NOOP */ 338 } 339