vchi_bsd.c revision 283291
1291716Sken/*- 2291716Sken * Copyright (c) 2010 Max Khon <fjoe@freebsd.org> 3291716Sken * All rights reserved. 4291716Sken * 5291716Sken * This software was developed by Max Khon under sponsorship from 6291716Sken * the FreeBSD Foundation and Ethon Technologies GmbH. 7291716Sken * 8291716Sken * Redistribution and use in source and binary forms, with or without 9291716Sken * modification, are permitted provided that the following conditions 10291716Sken * are met: 11291716Sken * 1. Redistributions of source code must retain the above copyright 12291716Sken * notice, this list of conditions and the following disclaimer. 13291716Sken * 2. Redistributions in binary form must reproduce the above copyright 14291716Sken * notice, this list of conditions and the following disclaimer in the 15291716Sken * documentation and/or other materials provided with the distribution. 16291716Sken * 17291716Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18291716Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19291716Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20291716Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21291716Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22291716Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23291716Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24291716Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25291716Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26291716Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27291716Sken * SUCH DAMAGE. 28291716Sken * 29291716Sken * $Id: bsd-compat.c 9253 2010-09-02 10:12:09Z fjoe $ 30291716Sken */ 31291716Sken 32291716Sken#include <sys/types.h> 33291716Sken#include <sys/limits.h> 34291716Sken#include <sys/bus.h> 35291716Sken#include <sys/callout.h> 36291716Sken#include <sys/firmware.h> 37291716Sken#include <sys/param.h> 38291716Sken#include <sys/proc.h> 39291716Sken#include <sys/syscallsubr.h> 40291716Sken#include <sys/systm.h> 41291716Sken#include <sys/taskqueue.h> 42291716Sken 43291716Sken#include <machine/stdarg.h> 44291716Sken 45291716Sken#include "mbox_if.h" 46291716Sken 47291716Sken#include <interface/compat/vchi_bsd.h> 48291716Sken 49291716SkenMALLOC_DEFINE(M_VCHI, "VCHI", "VCHI"); 50291716Sken 51291716Sken/* 52291716Sken * Timer API 53291716Sken */ 54291716Skenstatic void 55291716Skenrun_timer(void *arg) 56291716Sken{ 57291716Sken struct timer_list *t = (struct timer_list *) arg; 58291716Sken void (*function)(unsigned long); 59291716Sken 60291716Sken mtx_lock_spin(&t->mtx); 61291716Sken if (callout_pending(&t->callout)) { 62291716Sken /* callout was reset */ 63291716Sken mtx_unlock_spin(&t->mtx); 64291716Sken return; 65291716Sken } 66291716Sken if (!callout_active(&t->callout)) { 67291716Sken /* callout was stopped */ 68291716Sken mtx_unlock_spin(&t->mtx); 69291716Sken return; 70291716Sken } 71291716Sken callout_deactivate(&t->callout); 72291716Sken 73291716Sken function = t->function; 74291716Sken mtx_unlock_spin(&t->mtx); 75291716Sken 76291716Sken function(t->data); 77291716Sken} 78291716Sken 79291716Skenvoid 80291716Skeninit_timer(struct timer_list *t) 81291716Sken{ 82291716Sken mtx_init(&t->mtx, "dahdi timer lock", NULL, MTX_SPIN); 83291716Sken callout_init(&t->callout, 1); 84291716Sken t->expires = 0; 85291716Sken /* 86291716Sken * function and data are not initialized intentionally: 87291716Sken * they are not initialized by Linux implementation too 88291716Sken */ 89291716Sken} 90291716Sken 91291716Skenvoid 92291716Skensetup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data) 93291716Sken{ 94291716Sken t->function = function; 95291716Sken t->data = data; 96291716Sken init_timer(t); 97291716Sken} 98291716Sken 99291716Skenvoid 100291716Skenmod_timer(struct timer_list *t, unsigned long expires) 101291716Sken{ 102291716Sken mtx_lock_spin(&t->mtx); 103291716Sken callout_reset(&t->callout, expires - jiffies, run_timer, t); 104291716Sken mtx_unlock_spin(&t->mtx); 105291716Sken} 106291716Sken 107291716Skenvoid 108291716Skenadd_timer(struct timer_list *t) 109291716Sken{ 110291716Sken mod_timer(t, t->expires); 111291716Sken} 112291716Sken 113291716Skenint 114291716Skendel_timer_sync(struct timer_list *t) 115291716Sken{ 116291716Sken mtx_lock_spin(&t->mtx); 117291716Sken callout_stop(&t->callout); 118291716Sken mtx_unlock_spin(&t->mtx); 119291716Sken 120291716Sken mtx_destroy(&t->mtx); 121291716Sken return 0; 122291716Sken} 123291716Sken 124291716Skenint 125291716Skendel_timer(struct timer_list *t) 126291716Sken{ 127291716Sken del_timer_sync(t); 128291716Sken return 0; 129291716Sken} 130291716Sken 131291716Sken/* 132291716Sken * Completion API 133291716Sken */ 134291716Skenvoid 135291716Skeninit_completion(struct completion *c) 136291716Sken{ 137291716Sken cv_init(&c->cv, "VCHI completion cv"); 138291716Sken mtx_init(&c->lock, "VCHI completion lock", "condvar", MTX_DEF); 139291716Sken c->done = 0; 140291716Sken} 141291716Sken 142291716Skenvoid 143291716Skendestroy_completion(struct completion *c) 144291716Sken{ 145291716Sken cv_destroy(&c->cv); 146291716Sken mtx_destroy(&c->lock); 147291716Sken} 148291716Sken 149291716Skenvoid 150291716Skencomplete(struct completion *c) 151291716Sken{ 152291716Sken mtx_lock(&c->lock); 153291716Sken 154291716Sken if (c->done >= 0) { 155291716Sken KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */ 156291716Sken c->done++; 157291716Sken cv_signal(&c->cv); 158291716Sken } else { 159291716Sken KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 160291716Sken } 161291716Sken 162291716Sken mtx_unlock(&c->lock); 163291716Sken} 164291716Sken 165291716Skenvoid 166291716Skencomplete_all(struct completion *c) 167291716Sken{ 168291716Sken mtx_lock(&c->lock); 169291716Sken 170291716Sken if (c->done >= 0) { 171291716Sken KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */ 172291716Sken c->done = -1; 173291716Sken cv_broadcast(&c->cv); 174291716Sken } else { 175291716Sken KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 176291716Sken } 177291716Sken 178291716Sken mtx_unlock(&c->lock); 179291716Sken} 180291716Sken 181291716Skenvoid 182291716SkenINIT_COMPLETION_locked(struct completion *c) 183291716Sken{ 184291716Sken mtx_lock(&c->lock); 185291716Sken 186291716Sken c->done = 0; 187291716Sken 188291716Sken mtx_unlock(&c->lock); 189291716Sken} 190291716Sken 191291716Skenstatic void 192291716Sken_completion_claim(struct completion *c) 193291716Sken{ 194291716Sken 195291716Sken KASSERT(mtx_owned(&c->lock), 196291716Sken ("_completion_claim should be called with acquired lock")); 197291716Sken KASSERT(c->done != 0, ("_completion_claim on non-waited completion")); 198291716Sken if (c->done > 0) 199291716Sken c->done--; 200291716Sken else 201291716Sken KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 202291716Sken} 203291716Sken 204291716Skenvoid 205291716Skenwait_for_completion(struct completion *c) 206291716Sken{ 207291716Sken mtx_lock(&c->lock); 208291716Sken if (!c->done) 209291716Sken cv_wait(&c->cv, &c->lock); 210291716Sken c->done--; 211291716Sken mtx_unlock(&c->lock); 212291716Sken} 213291716Sken 214291716Skenint 215291716Skentry_wait_for_completion(struct completion *c) 216291716Sken{ 217291716Sken int res = 0; 218291716Sken 219291716Sken mtx_lock(&c->lock); 220291716Sken if (!c->done) 221291716Sken res = 1; 222291716Sken else 223291716Sken c->done--; 224291716Sken mtx_unlock(&c->lock); 225291716Sken return res == 0; 226291716Sken} 227291716Sken 228291716Skenint 229291716Skenwait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout) 230291716Sken{ 231291716Sken int res = 0; 232291716Sken unsigned long start, now; 233291716Sken start = jiffies; 234291716Sken 235291716Sken mtx_lock(&c->lock); 236291716Sken while (c->done == 0) { 237291716Sken res = cv_timedwait_sig(&c->cv, &c->lock, timeout); 238291716Sken if (res) 239291716Sken goto out; 240291716Sken now = jiffies; 241291716Sken if (timeout < (now - start)) { 242291716Sken res = EWOULDBLOCK; 243291716Sken goto out; 244291716Sken } 245291716Sken 246291716Sken timeout -= (now - start); 247291716Sken start = now; 248291716Sken } 249291716Sken 250291716Sken _completion_claim(c); 251291716Sken res = 0; 252291716Sken 253291716Skenout: 254291716Sken mtx_unlock(&c->lock); 255291716Sken 256291716Sken if (res == EWOULDBLOCK) { 257291716Sken return 0; 258291716Sken } else if ((res == EINTR) || (res == ERESTART)) { 259291716Sken return -ERESTART; 260291716Sken } else { 261291716Sken KASSERT((res == 0), ("res = %d", res)); 262291716Sken return timeout; 263291716Sken } 264291716Sken} 265291716Sken 266291716Skenint 267291716Skenwait_for_completion_interruptible(struct completion *c) 268291716Sken{ 269291716Sken int res = 0; 270291716Sken 271291716Sken mtx_lock(&c->lock); 272291716Sken while (c->done == 0) { 273291716Sken res = cv_wait_sig(&c->cv, &c->lock); 274291716Sken if (res) 275291716Sken goto out; 276291716Sken } 277291716Sken 278291716Sken _completion_claim(c); 279291716Sken 280291716Skenout: 281291716Sken mtx_unlock(&c->lock); 282291716Sken 283291716Sken 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 printf("sema_sysinit\n"); 304 _sema_init(s, 1); 305} 306 307void 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 317void 318_sema_destroy(struct semaphore *s) 319{ 320 mtx_destroy(&s->mtx); 321 cv_destroy(&s->cv); 322} 323 324void 325down(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 339int 340down_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 368int 369down_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 390void 391up(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 */ 404void 405rlprintf(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 418void 419device_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 437void 438flush_signals(VCHIQ_THREAD_T thr) 439{ 440 printf("Implement ME: %s\n", __func__); 441} 442 443int 444fatal_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 458static int thread_data_slot = 0; 459 460struct thread_data { 461 void *data; 462 int (*threadfn)(void *); 463}; 464 465static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS]; 466 467static void 468kthread_wrapper(void *data) 469{ 470 struct thread_data *slot; 471 472 slot = data; 473 slot->threadfn(slot->data); 474} 475 476VCHIQ_THREAD_T 477vchiq_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 511void 512set_user_nice(VCHIQ_THREAD_T thr, int nice) 513{ 514 /* NOOP */ 515} 516 517void 518wake_up_process(VCHIQ_THREAD_T thr) 519{ 520 /* NOOP */ 521} 522 523void 524bcm_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