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.3 2013/09/06 05:50:22 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_stop(&t->callout); 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 * Completion API 125 */ 126 void 127 init_completion(struct completion *c) 128 { 129 cv_init(&c->cv, "VCHI completion cv"); 130 mutex_init(&c->lock, MUTEX_DEFAULT, IPL_NONE); 131 c->done = 0; 132 } 133 134 void 135 destroy_completion(struct completion *c) 136 { 137 cv_destroy(&c->cv); 138 mutex_destroy(&c->lock); 139 } 140 141 void 142 wait_for_completion(struct completion *c) 143 { 144 mutex_enter(&c->lock); 145 if (!c->done) 146 cv_wait(&c->cv, &c->lock); 147 c->done--; 148 mutex_exit(&c->lock); 149 } 150 151 int 152 try_wait_for_completion(struct completion *c) 153 { 154 int res = 0; 155 156 mutex_enter(&c->lock); 157 if (!c->done) 158 c->done--; 159 else 160 res = 1; 161 mutex_exit(&c->lock); 162 return res != 0; 163 } 164 165 int 166 wait_for_completion_timeout(struct completion *c, unsigned long timeout) 167 { 168 int res = 0; 169 170 mutex_enter(&c->lock); 171 if (!c->done) 172 res = cv_timedwait(&c->cv, &c->lock, timeout); 173 if (res == 0) 174 c->done--; 175 mutex_exit(&c->lock); 176 return res != 0; 177 } 178 179 int 180 wait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout) 181 { 182 int res = 0; 183 184 mutex_enter(&c->lock); 185 if (!c->done) 186 res = cv_timedwait_sig(&c->cv, &c->lock, timeout); 187 if (res == 0) 188 c->done--; 189 mutex_exit(&c->lock); 190 return res != 0; 191 } 192 193 int 194 wait_for_completion_interruptible(struct completion *c) 195 { 196 int res = 0; 197 198 mutex_enter(&c->lock); 199 if (!c->done) 200 res = cv_wait_sig(&c->cv, &c->lock); 201 if (res == 0) 202 c->done--; 203 mutex_exit(&c->lock); 204 return res != 0; 205 } 206 207 int 208 wait_for_completion_killable(struct completion *c) 209 { 210 int res = 0; 211 212 mutex_enter(&c->lock); 213 if (!c->done) 214 res = cv_wait_sig(&c->cv, &c->lock); 215 /* TODO: check actual signals here ? */ 216 if (res == 0) 217 c->done--; 218 mutex_exit(&c->lock); 219 return res != 0; 220 } 221 222 void 223 complete(struct completion *c) 224 { 225 mutex_enter(&c->lock); 226 c->done++; 227 cv_signal(&c->cv); 228 mutex_exit(&c->lock); 229 } 230 231 void 232 complete_all(struct completion *c) 233 { 234 mutex_enter(&c->lock); 235 c->done++; 236 cv_broadcast(&c->cv); 237 mutex_exit(&c->lock); 238 } 239 240 /* 241 * Semaphore API 242 */ 243 244 void sema_sysinit(void *arg) 245 { 246 struct semaphore *s = arg; 247 248 printf("sema_sysinit\n"); 249 _sema_init(s, 1); 250 } 251 252 void 253 _sema_init(struct semaphore *s, int value) 254 { 255 bzero(s, sizeof(*s)); 256 mutex_init(&s->mtx, MUTEX_DEFAULT, IPL_VM); 257 cv_init(&s->cv, "semacv"); 258 s->value = value; 259 } 260 261 void 262 _sema_destroy(struct semaphore *s) 263 { 264 mutex_destroy(&s->mtx); 265 cv_destroy(&s->cv); 266 } 267 268 void 269 down(struct semaphore *s) 270 { 271 272 mutex_enter(&s->mtx); 273 while (s->value == 0) { 274 s->waiters++; 275 cv_wait(&s->cv, &s->mtx); 276 s->waiters--; 277 } 278 279 s->value--; 280 mutex_exit(&s->mtx); 281 } 282 283 int 284 down_interruptible(struct semaphore *s) 285 { 286 int ret ; 287 288 ret = 0; 289 290 mutex_enter(&s->mtx); 291 292 while (s->value == 0) { 293 s->waiters++; 294 ret = cv_wait_sig(&s->cv, &s->mtx); 295 s->waiters--; 296 297 if (ret == EINTR || ret == ERESTART) { 298 mutex_exit(&s->mtx); 299 return (-EINTR); 300 } 301 } 302 303 s->value--; 304 mutex_exit(&s->mtx); 305 306 return (0); 307 } 308 309 int 310 down_trylock(struct semaphore *s) 311 { 312 int ret; 313 314 ret = 0; 315 316 mutex_enter(&s->mtx); 317 318 if (s->value > 0) { 319 /* Success. */ 320 s->value--; 321 ret = 0; 322 } else { 323 ret = -EAGAIN; 324 } 325 326 mutex_exit(&s->mtx); 327 328 return (ret); 329 } 330 331 void 332 up(struct semaphore *s) 333 { 334 mutex_enter(&s->mtx); 335 s->value++; 336 if (s->waiters && s->value > 0) 337 cv_signal(&s->cv); 338 339 mutex_exit(&s->mtx); 340 } 341 342 /* 343 * Logging API 344 */ 345 void 346 rlprintf(int pps, const char *fmt, ...) 347 { 348 va_list ap; 349 static struct timeval last_printf; 350 static int count; 351 352 if (ppsratecheck(&last_printf, &count, pps)) { 353 va_start(ap, fmt); 354 vprintf(fmt, ap); 355 va_end(ap); 356 } 357 } 358 359 void 360 device_rlprintf(int pps, device_t dev, const char *fmt, ...) 361 { 362 va_list ap; 363 static struct timeval last_printf; 364 static int count; 365 366 if (ppsratecheck(&last_printf, &count, pps)) { 367 va_start(ap, fmt); 368 device_print_prettyname(dev); 369 vprintf(fmt, ap); 370 va_end(ap); 371 } 372 } 373 374 /* 375 * Signals API 376 */ 377 378 void 379 flush_signals(VCHIQ_THREAD_T thr) 380 { 381 printf("Implement ME: %s\n", __func__); 382 } 383 384 int 385 fatal_signal_pending(VCHIQ_THREAD_T thr) 386 { 387 printf("Implement ME: %s\n", __func__); 388 return (0); 389 } 390 391 /* 392 * kthread API 393 */ 394 395 /* 396 * This is a hack to avoid memory leak 397 */ 398 #define MAX_THREAD_DATA_SLOTS 32 399 static int thread_data_slot = 0; 400 401 struct thread_data { 402 void *data; 403 int (*threadfn)(void *); 404 }; 405 406 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS]; 407 408 static void 409 kthread_wrapper(void *data) 410 { 411 struct thread_data *slot; 412 413 slot = data; 414 slot->threadfn(slot->data); 415 } 416 417 VCHIQ_THREAD_T 418 vchiq_thread_create(int (*threadfn)(void *data), 419 void *data, 420 const char namefmt[], ...) 421 { 422 VCHIQ_THREAD_T newt; 423 va_list ap; 424 char name[MAXCOMLEN+1]; 425 struct thread_data *slot; 426 427 if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) { 428 printf("kthread_create: out of thread data slots\n"); 429 return (NULL); 430 } 431 432 slot = &thread_slots[thread_data_slot]; 433 slot->data = data; 434 slot->threadfn = threadfn; 435 436 va_start(ap, namefmt); 437 vsnprintf(name, sizeof(name), namefmt, ap); 438 va_end(ap); 439 440 newt = NULL; 441 if (kthread_create(PRI_NONE, 0, NULL, kthread_wrapper, slot, &newt, 442 "%s", name) != 0) { 443 /* Just to be sure */ 444 newt = NULL; 445 } else { 446 thread_data_slot++; 447 } 448 449 return newt; 450 } 451 452 void 453 set_user_nice(VCHIQ_THREAD_T thr, int nice) 454 { 455 /* NOOP */ 456 } 457 458 void 459 wake_up_process(VCHIQ_THREAD_T thr) 460 { 461 /* NOOP */ 462 } 463