vchi_bsd.c revision 302408
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 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