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 mtx_lock(&s->mtx); 344 345 while (s->value == 0) { 346 s->waiters++; 347 ret = cv_wait_sig(&s->cv, &s->mtx); 348 s->waiters--; 349 350 /* XXXMDC As per its semaphore.c, linux can only return EINTR */ 351 if (ret) { 352 mtx_unlock(&s->mtx); 353 return -EINTR; 354 } 355 } 356 357 s->value--; 358 mtx_unlock(&s->mtx); 359 360 return (0); 361 } 362 363 int 364 down_trylock(struct semaphore *s) 365 { 366 int ret; 367 368 ret = 0; 369 370 mtx_lock(&s->mtx); 371 372 if (s->value > 0) { 373 /* Success. */ 374 s->value--; 375 ret = 0; 376 } else { 377 ret = -EAGAIN; 378 } 379 380 mtx_unlock(&s->mtx); 381 382 return (ret); 383 } 384 385 void 386 up(struct semaphore *s) 387 { 388 mtx_lock(&s->mtx); 389 s->value++; 390 if (s->waiters && s->value > 0) 391 cv_signal(&s->cv); 392 393 mtx_unlock(&s->mtx); 394 } 395 396 /* 397 * Logging API 398 */ 399 void 400 rlprintf(int pps, const char *fmt, ...) 401 { 402 va_list ap; 403 static struct timeval last_printf; 404 static int count; 405 406 if (ppsratecheck(&last_printf, &count, pps)) { 407 va_start(ap, fmt); 408 vprintf(fmt, ap); 409 va_end(ap); 410 } 411 } 412 413 void 414 device_rlprintf(int pps, device_t dev, const char *fmt, ...) 415 { 416 va_list ap; 417 static struct timeval last_printf; 418 static int count; 419 420 if (ppsratecheck(&last_printf, &count, pps)) { 421 va_start(ap, fmt); 422 device_print_prettyname(dev); 423 vprintf(fmt, ap); 424 va_end(ap); 425 } 426 } 427 428 /* 429 * Signals API 430 */ 431 432 void 433 flush_signals(VCHIQ_THREAD_T thr) 434 { 435 printf("Implement ME: %s\n", __func__); 436 } 437 438 int 439 fatal_signal_pending(VCHIQ_THREAD_T thr) 440 { 441 return (curproc_sigkilled()); 442 } 443 444 /* 445 * kthread API 446 */ 447 448 /* 449 * This is a hack to avoid memory leak 450 */ 451 #define MAX_THREAD_DATA_SLOTS 32 452 static int thread_data_slot = 0; 453 454 struct thread_data { 455 void *data; 456 int (*threadfn)(void *); 457 }; 458 459 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS]; 460 461 static void 462 kthread_wrapper(void *data) 463 { 464 struct thread_data *slot; 465 466 slot = data; 467 slot->threadfn(slot->data); 468 } 469 470 VCHIQ_THREAD_T 471 vchiq_thread_create(int (*threadfn)(void *data), 472 void *data, 473 const char namefmt[], ...) 474 { 475 VCHIQ_THREAD_T newp; 476 va_list ap; 477 char name[MAXCOMLEN+1]; 478 struct thread_data *slot; 479 480 if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) { 481 printf("kthread_create: out of thread data slots\n"); 482 return (NULL); 483 } 484 485 slot = &thread_slots[thread_data_slot]; 486 slot->data = data; 487 slot->threadfn = threadfn; 488 489 va_start(ap, namefmt); 490 vsnprintf(name, sizeof(name), namefmt, ap); 491 va_end(ap); 492 493 newp = NULL; 494 if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0, 495 "%s", name) != 0) { 496 /* Just to be sure */ 497 newp = NULL; 498 } 499 else 500 thread_data_slot++; 501 502 return newp; 503 } 504 505 void 506 set_user_nice(VCHIQ_THREAD_T thr, int nice) 507 { 508 /* NOOP */ 509 } 510 511 void 512 wake_up_process(VCHIQ_THREAD_T thr) 513 { 514 /* NOOP */ 515 } 516 517 void 518 bcm_mbox_write(int channel, uint32_t data) 519 { 520 device_t mbox; 521 522 mbox = devclass_get_device(devclass_find("mbox"), 0); 523 524 if (mbox) 525 MBOX_WRITE(mbox, channel, data); 526 } 527