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