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 49MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI"); 50 51/* 52 * Timer API 53 */ 54static void 55run_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 79void 80init_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 91void 92setup_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 99void 100mod_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 107void 108add_timer(struct timer_list *t) 109{ 110 mod_timer(t, t->expires); 111} 112 113int 114del_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 124int 125del_timer(struct timer_list *t) 126{ 127 del_timer_sync(t); 128 return 0; 129} 130 131/* 132 * Completion API 133 */ 134void 135init_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 142void 143destroy_completion(struct completion *c) 144{ 145 cv_destroy(&c->cv); 146 mtx_destroy(&c->lock); 147} 148 149void 150complete(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 165void 166complete_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 181void 182INIT_COMPLETION_locked(struct completion *c) 183{ 184 mtx_lock(&c->lock); 185 186 c->done = 0; 187 188 mtx_unlock(&c->lock); 189} 190 191static 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 204void 205wait_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 214int 215try_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 228int 229wait_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 253out: 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 266int 267wait_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 280out: 281 mtx_unlock(&c->lock); 282 283 if ((res == EINTR) || (res == ERESTART)) 284 res = -ERESTART; 285 return res; 286} 287 288int 289wait_for_completion_killable(struct completion *c) 290{ 291 292 return wait_for_completion_interruptible(c); 293} 294 295/* 296 * Semaphore API 297 */ 298 299void sema_sysinit(void *arg) 300{ 301 struct semaphore *s = arg; 302 303 _sema_init(s, 1); 304} 305 306void 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 316void 317_sema_destroy(struct semaphore *s) 318{ 319 mtx_destroy(&s->mtx); 320 cv_destroy(&s->cv); 321} 322 323void 324down(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 338int 339down_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 367int 368down_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 389void 390up(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 */ 403void 404rlprintf(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 417void 418device_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 436void 437flush_signals(VCHIQ_THREAD_T thr) 438{ 439 printf("Implement ME: %s\n", __func__); 440} 441 442int 443fatal_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 457static int thread_data_slot = 0; 458 459struct thread_data { 460 void *data; 461 int (*threadfn)(void *); 462}; 463 464static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS]; 465 466static void 467kthread_wrapper(void *data) 468{ 469 struct thread_data *slot; 470 471 slot = data; 472 slot->threadfn(slot->data); 473} 474 475VCHIQ_THREAD_T 476vchiq_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 510void 511set_user_nice(VCHIQ_THREAD_T thr, int nice) 512{ 513 /* NOOP */ 514} 515 516void 517wake_up_process(VCHIQ_THREAD_T thr) 518{ 519 /* NOOP */ 520} 521 522void 523bcm_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