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: bsd-compat.c 9253 2010-09-02 10:12:09Z fjoe $ 30 */ 31 32 #include <sys/types.h> 33 #include <sys/limits.h> 34 #include <sys/bus.h> 35 #include <sys/callout.h> 36 #include <sys/firmware.h> 37 #include <sys/param.h> 38 #include <sys/proc.h> 39 #include <sys/stdarg.h> 40 #include <sys/syscallsubr.h> 41 #include <sys/systm.h> 42 #include <sys/taskqueue.h> 43 44 #include "mbox_if.h" 45 46 #include <interface/compat/vchi_bsd.h> 47 48 MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI"); 49 50 /* 51 * Timer API 52 */ 53 static void 54 run_timer(void *arg) 55 { 56 struct timer_list *t = (struct timer_list *) arg; 57 void (*function)(unsigned long); 58 59 mtx_lock_spin(&t->mtx); 60 if (callout_pending(&t->callout)) { 61 /* callout was reset */ 62 mtx_unlock_spin(&t->mtx); 63 return; 64 } 65 if (!callout_active(&t->callout)) { 66 /* callout was stopped */ 67 mtx_unlock_spin(&t->mtx); 68 return; 69 } 70 callout_deactivate(&t->callout); 71 72 function = t->function; 73 mtx_unlock_spin(&t->mtx); 74 75 function(t->data); 76 } 77 78 void 79 vchiq_init_timer(struct timer_list *t) 80 { 81 mtx_init(&t->mtx, "dahdi timer lock", NULL, MTX_SPIN); 82 callout_init(&t->callout, 1); 83 t->expires = 0; 84 /* 85 * function and data are not initialized intentionally: 86 * they are not initialized by Linux implementation too 87 */ 88 } 89 90 void 91 vchiq_setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data) 92 { 93 t->function = function; 94 t->data = data; 95 vchiq_init_timer(t); 96 } 97 98 void 99 vchiq_mod_timer(struct timer_list *t, unsigned long expires) 100 { 101 mtx_lock_spin(&t->mtx); 102 callout_reset(&t->callout, expires - jiffies, run_timer, t); 103 mtx_unlock_spin(&t->mtx); 104 } 105 106 void 107 vchiq_add_timer(struct timer_list *t) 108 { 109 vchiq_mod_timer(t, t->expires); 110 } 111 112 int 113 vchiq_del_timer_sync(struct timer_list *t) 114 { 115 mtx_lock_spin(&t->mtx); 116 callout_stop(&t->callout); 117 mtx_unlock_spin(&t->mtx); 118 119 mtx_destroy(&t->mtx); 120 return 0; 121 } 122 123 int 124 vchiq_del_timer(struct timer_list *t) 125 { 126 vchiq_del_timer_sync(t); 127 return 0; 128 } 129 130 /* 131 * Completion API 132 */ 133 void 134 init_completion(struct completion *c) 135 { 136 cv_init(&c->cv, "VCHI completion cv"); 137 mtx_init(&c->lock, "VCHI completion lock", "condvar", MTX_DEF); 138 c->done = 0; 139 } 140 141 void 142 destroy_completion(struct completion *c) 143 { 144 cv_destroy(&c->cv); 145 mtx_destroy(&c->lock); 146 } 147 148 void 149 complete(struct completion *c) 150 { 151 mtx_lock(&c->lock); 152 153 if (c->done >= 0) { 154 KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */ 155 c->done++; 156 cv_signal(&c->cv); 157 } else { 158 KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 159 } 160 161 mtx_unlock(&c->lock); 162 } 163 164 void 165 complete_all(struct completion *c) 166 { 167 mtx_lock(&c->lock); 168 169 if (c->done >= 0) { 170 KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */ 171 c->done = -1; 172 cv_broadcast(&c->cv); 173 } else { 174 KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 175 } 176 177 mtx_unlock(&c->lock); 178 } 179 180 void 181 INIT_COMPLETION_locked(struct completion *c) 182 { 183 mtx_lock(&c->lock); 184 185 c->done = 0; 186 187 mtx_unlock(&c->lock); 188 } 189 190 static void 191 _completion_claim(struct completion *c) 192 { 193 194 KASSERT(mtx_owned(&c->lock), 195 ("_completion_claim should be called with acquired lock")); 196 KASSERT(c->done != 0, ("_completion_claim on non-waited completion")); 197 if (c->done > 0) 198 c->done--; 199 else 200 KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 201 } 202 203 void 204 wait_for_completion(struct completion *c) 205 { 206 mtx_lock(&c->lock); 207 if (!c->done) 208 cv_wait(&c->cv, &c->lock); 209 c->done--; 210 mtx_unlock(&c->lock); 211 } 212 213 int 214 try_wait_for_completion(struct completion *c) 215 { 216 int res = 0; 217 218 mtx_lock(&c->lock); 219 if (!c->done) 220 res = 1; 221 else 222 c->done--; 223 mtx_unlock(&c->lock); 224 return res == 0; 225 } 226 227 int 228 wait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout) 229 { 230 int res = 0; 231 unsigned long start, now; 232 start = jiffies; 233 234 mtx_lock(&c->lock); 235 while (c->done == 0) { 236 res = cv_timedwait_sig(&c->cv, &c->lock, timeout); 237 if (res) 238 goto out; 239 now = jiffies; 240 if (timeout < (now - start)) { 241 res = EWOULDBLOCK; 242 goto out; 243 } 244 245 timeout -= (now - start); 246 start = now; 247 } 248 249 _completion_claim(c); 250 res = 0; 251 252 out: 253 mtx_unlock(&c->lock); 254 255 if (res == EWOULDBLOCK) { 256 return 0; 257 } else if ((res == EINTR) || (res == ERESTART)) { 258 return -ERESTART; 259 } else { 260 KASSERT((res == 0), ("res = %d", res)); 261 return timeout; 262 } 263 } 264 265 int 266 wait_for_completion_interruptible(struct completion *c) 267 { 268 int res = 0; 269 270 mtx_lock(&c->lock); 271 while (c->done == 0) { 272 res = cv_wait_sig(&c->cv, &c->lock); 273 if (res) 274 goto out; 275 } 276 277 _completion_claim(c); 278 279 out: 280 mtx_unlock(&c->lock); 281 282 if ((res == EINTR) || (res == ERESTART)) 283 res = -ERESTART; 284 return res; 285 } 286 287 int 288 wait_for_completion_killable(struct completion *c) 289 { 290 291 return wait_for_completion_interruptible(c); 292 } 293 294 /* 295 * Semaphore API 296 */ 297 298 void sema_sysinit(void *arg) 299 { 300 struct semaphore *s = arg; 301 302 _sema_init(s, 1); 303 } 304 305 void 306 _sema_init(struct semaphore *s, int value) 307 { 308 bzero(s, sizeof(*s)); 309 mtx_init(&s->mtx, "sema lock", "VCHIQ sepmaphore backing lock", 310 MTX_DEF | MTX_NOWITNESS | MTX_QUIET); 311 cv_init(&s->cv, "sema cv"); 312 s->value = value; 313 } 314 315 void 316 _sema_destroy(struct semaphore *s) 317 { 318 mtx_destroy(&s->mtx); 319 cv_destroy(&s->cv); 320 } 321 322 void 323 down(struct semaphore *s) 324 { 325 326 mtx_lock(&s->mtx); 327 while (s->value == 0) { 328 s->waiters++; 329 cv_wait(&s->cv, &s->mtx); 330 s->waiters--; 331 } 332 333 s->value--; 334 mtx_unlock(&s->mtx); 335 } 336 337 int 338 down_interruptible(struct semaphore *s) 339 { 340 int ret ; 341 342 ret = 0; 343 344 mtx_lock(&s->mtx); 345 346 while (s->value == 0) { 347 s->waiters++; 348 ret = cv_wait_sig(&s->cv, &s->mtx); 349 s->waiters--; 350 351 if (ret == EINTR) { 352 mtx_unlock(&s->mtx); 353 return (-EINTR); 354 } 355 356 if (ret == ERESTART) 357 continue; 358 } 359 360 s->value--; 361 mtx_unlock(&s->mtx); 362 363 return (0); 364 } 365 366 int 367 down_trylock(struct semaphore *s) 368 { 369 int ret; 370 371 ret = 0; 372 373 mtx_lock(&s->mtx); 374 375 if (s->value > 0) { 376 /* Success. */ 377 s->value--; 378 ret = 0; 379 } else { 380 ret = -EAGAIN; 381 } 382 383 mtx_unlock(&s->mtx); 384 385 return (ret); 386 } 387 388 void 389 up(struct semaphore *s) 390 { 391 mtx_lock(&s->mtx); 392 s->value++; 393 if (s->waiters && s->value > 0) 394 cv_signal(&s->cv); 395 396 mtx_unlock(&s->mtx); 397 } 398 399 /* 400 * Logging API 401 */ 402 void 403 rlprintf(int pps, const char *fmt, ...) 404 { 405 va_list ap; 406 static struct timeval last_printf; 407 static int count; 408 409 if (ppsratecheck(&last_printf, &count, pps)) { 410 va_start(ap, fmt); 411 vprintf(fmt, ap); 412 va_end(ap); 413 } 414 } 415 416 void 417 device_rlprintf(int pps, device_t dev, const char *fmt, ...) 418 { 419 va_list ap; 420 static struct timeval last_printf; 421 static int count; 422 423 if (ppsratecheck(&last_printf, &count, pps)) { 424 va_start(ap, fmt); 425 device_print_prettyname(dev); 426 vprintf(fmt, ap); 427 va_end(ap); 428 } 429 } 430 431 /* 432 * Signals API 433 */ 434 435 void 436 flush_signals(VCHIQ_THREAD_T thr) 437 { 438 printf("Implement ME: %s\n", __func__); 439 } 440 441 int 442 fatal_signal_pending(VCHIQ_THREAD_T thr) 443 { 444 printf("Implement ME: %s\n", __func__); 445 return (0); 446 } 447 448 /* 449 * kthread API 450 */ 451 452 /* 453 * This is a hack to avoid memory leak 454 */ 455 #define MAX_THREAD_DATA_SLOTS 32 456 static int thread_data_slot = 0; 457 458 struct thread_data { 459 void *data; 460 int (*threadfn)(void *); 461 }; 462 463 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS]; 464 465 static void 466 kthread_wrapper(void *data) 467 { 468 struct thread_data *slot; 469 470 slot = data; 471 slot->threadfn(slot->data); 472 } 473 474 VCHIQ_THREAD_T 475 vchiq_thread_create(int (*threadfn)(void *data), 476 void *data, 477 const char namefmt[], ...) 478 { 479 VCHIQ_THREAD_T newp; 480 va_list ap; 481 char name[MAXCOMLEN+1]; 482 struct thread_data *slot; 483 484 if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) { 485 printf("kthread_create: out of thread data slots\n"); 486 return (NULL); 487 } 488 489 slot = &thread_slots[thread_data_slot]; 490 slot->data = data; 491 slot->threadfn = threadfn; 492 493 va_start(ap, namefmt); 494 vsnprintf(name, sizeof(name), namefmt, ap); 495 va_end(ap); 496 497 newp = NULL; 498 if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0, 499 "%s", name) != 0) { 500 /* Just to be sure */ 501 newp = NULL; 502 } 503 else 504 thread_data_slot++; 505 506 return newp; 507 } 508 509 void 510 set_user_nice(VCHIQ_THREAD_T thr, int nice) 511 { 512 /* NOOP */ 513 } 514 515 void 516 wake_up_process(VCHIQ_THREAD_T thr) 517 { 518 /* NOOP */ 519 } 520 521 void 522 bcm_mbox_write(int channel, uint32_t data) 523 { 524 device_t mbox; 525 526 mbox = devclass_get_device(devclass_find("mbox"), 0); 527 528 if (mbox) 529 MBOX_WRITE(mbox, channel, data); 530 } 531