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