1278277Sgonzo/*- 2278277Sgonzo * Copyright (c) 2010 Max Khon <fjoe@freebsd.org> 3278277Sgonzo * All rights reserved. 4278277Sgonzo * 5278277Sgonzo * This software was developed by Max Khon under sponsorship from 6278277Sgonzo * the FreeBSD Foundation and Ethon Technologies GmbH. 7278277Sgonzo * 8278277Sgonzo * Redistribution and use in source and binary forms, with or without 9278277Sgonzo * modification, are permitted provided that the following conditions 10278277Sgonzo * are met: 11278277Sgonzo * 1. Redistributions of source code must retain the above copyright 12278277Sgonzo * notice, this list of conditions and the following disclaimer. 13278277Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 14278277Sgonzo * notice, this list of conditions and the following disclaimer in the 15278277Sgonzo * documentation and/or other materials provided with the distribution. 16278277Sgonzo * 17278277Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18278277Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19278277Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20278277Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21278277Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22278277Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23278277Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24278277Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25278277Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26278277Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27278277Sgonzo * SUCH DAMAGE. 28278277Sgonzo * 29278277Sgonzo * $Id: bsd-compat.c 9253 2010-09-02 10:12:09Z fjoe $ 30278277Sgonzo */ 31278277Sgonzo 32278277Sgonzo#include <sys/types.h> 33278277Sgonzo#include <sys/limits.h> 34278277Sgonzo#include <sys/bus.h> 35278277Sgonzo#include <sys/callout.h> 36278277Sgonzo#include <sys/firmware.h> 37278277Sgonzo#include <sys/param.h> 38278277Sgonzo#include <sys/proc.h> 39278277Sgonzo#include <sys/syscallsubr.h> 40278277Sgonzo#include <sys/systm.h> 41278277Sgonzo#include <sys/taskqueue.h> 42278277Sgonzo 43278277Sgonzo#include <machine/stdarg.h> 44278277Sgonzo 45278277Sgonzo#include "mbox_if.h" 46278277Sgonzo 47278277Sgonzo#include <interface/compat/vchi_bsd.h> 48278277Sgonzo 49278277SgonzoMALLOC_DEFINE(M_VCHI, "VCHI", "VCHI"); 50278277Sgonzo 51278277Sgonzo/* 52278277Sgonzo * Timer API 53278277Sgonzo */ 54278277Sgonzostatic void 55278277Sgonzorun_timer(void *arg) 56278277Sgonzo{ 57278277Sgonzo struct timer_list *t = (struct timer_list *) arg; 58278277Sgonzo void (*function)(unsigned long); 59278277Sgonzo 60278277Sgonzo mtx_lock_spin(&t->mtx); 61278277Sgonzo if (callout_pending(&t->callout)) { 62278277Sgonzo /* callout was reset */ 63278277Sgonzo mtx_unlock_spin(&t->mtx); 64278277Sgonzo return; 65278277Sgonzo } 66278277Sgonzo if (!callout_active(&t->callout)) { 67278277Sgonzo /* callout was stopped */ 68278277Sgonzo mtx_unlock_spin(&t->mtx); 69278277Sgonzo return; 70278277Sgonzo } 71278277Sgonzo callout_deactivate(&t->callout); 72278277Sgonzo 73278277Sgonzo function = t->function; 74278277Sgonzo mtx_unlock_spin(&t->mtx); 75278277Sgonzo 76278277Sgonzo function(t->data); 77278277Sgonzo} 78278277Sgonzo 79278277Sgonzovoid 80278277Sgonzoinit_timer(struct timer_list *t) 81278277Sgonzo{ 82278277Sgonzo mtx_init(&t->mtx, "dahdi timer lock", NULL, MTX_SPIN); 83283291Sjkim callout_init(&t->callout, 1); 84278277Sgonzo t->expires = 0; 85278277Sgonzo /* 86278277Sgonzo * function and data are not initialized intentionally: 87278277Sgonzo * they are not initialized by Linux implementation too 88278277Sgonzo */ 89278277Sgonzo} 90278277Sgonzo 91278277Sgonzovoid 92278277Sgonzosetup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data) 93278277Sgonzo{ 94278277Sgonzo t->function = function; 95278277Sgonzo t->data = data; 96278277Sgonzo init_timer(t); 97278277Sgonzo} 98278277Sgonzo 99278277Sgonzovoid 100278277Sgonzomod_timer(struct timer_list *t, unsigned long expires) 101278277Sgonzo{ 102278277Sgonzo mtx_lock_spin(&t->mtx); 103278277Sgonzo callout_reset(&t->callout, expires - jiffies, run_timer, t); 104278277Sgonzo mtx_unlock_spin(&t->mtx); 105278277Sgonzo} 106278277Sgonzo 107278277Sgonzovoid 108278277Sgonzoadd_timer(struct timer_list *t) 109278277Sgonzo{ 110278277Sgonzo mod_timer(t, t->expires); 111278277Sgonzo} 112278277Sgonzo 113278277Sgonzoint 114278277Sgonzodel_timer_sync(struct timer_list *t) 115278277Sgonzo{ 116278277Sgonzo mtx_lock_spin(&t->mtx); 117278277Sgonzo callout_stop(&t->callout); 118278277Sgonzo mtx_unlock_spin(&t->mtx); 119278277Sgonzo 120278277Sgonzo mtx_destroy(&t->mtx); 121278277Sgonzo return 0; 122278277Sgonzo} 123278277Sgonzo 124278277Sgonzoint 125278277Sgonzodel_timer(struct timer_list *t) 126278277Sgonzo{ 127278277Sgonzo del_timer_sync(t); 128278277Sgonzo return 0; 129278277Sgonzo} 130278277Sgonzo 131278277Sgonzo/* 132278277Sgonzo * Completion API 133278277Sgonzo */ 134278277Sgonzovoid 135278277Sgonzoinit_completion(struct completion *c) 136278277Sgonzo{ 137278277Sgonzo cv_init(&c->cv, "VCHI completion cv"); 138278277Sgonzo mtx_init(&c->lock, "VCHI completion lock", "condvar", MTX_DEF); 139278277Sgonzo c->done = 0; 140278277Sgonzo} 141278277Sgonzo 142278277Sgonzovoid 143278277Sgonzodestroy_completion(struct completion *c) 144278277Sgonzo{ 145278277Sgonzo cv_destroy(&c->cv); 146278277Sgonzo mtx_destroy(&c->lock); 147278277Sgonzo} 148278277Sgonzo 149278277Sgonzovoid 150278277Sgonzocomplete(struct completion *c) 151278277Sgonzo{ 152278277Sgonzo mtx_lock(&c->lock); 153278277Sgonzo 154278277Sgonzo if (c->done >= 0) { 155278277Sgonzo KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */ 156278277Sgonzo c->done++; 157278277Sgonzo cv_signal(&c->cv); 158278277Sgonzo } else { 159278277Sgonzo KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 160278277Sgonzo } 161278277Sgonzo 162278277Sgonzo mtx_unlock(&c->lock); 163278277Sgonzo} 164278277Sgonzo 165278277Sgonzovoid 166278277Sgonzocomplete_all(struct completion *c) 167278277Sgonzo{ 168278277Sgonzo mtx_lock(&c->lock); 169278277Sgonzo 170278277Sgonzo if (c->done >= 0) { 171278277Sgonzo KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */ 172278277Sgonzo c->done = -1; 173278277Sgonzo cv_broadcast(&c->cv); 174278277Sgonzo } else { 175278277Sgonzo KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 176278277Sgonzo } 177278277Sgonzo 178278277Sgonzo mtx_unlock(&c->lock); 179278277Sgonzo} 180278277Sgonzo 181278277Sgonzovoid 182278277SgonzoINIT_COMPLETION_locked(struct completion *c) 183278277Sgonzo{ 184278277Sgonzo mtx_lock(&c->lock); 185278277Sgonzo 186278277Sgonzo c->done = 0; 187278277Sgonzo 188278277Sgonzo mtx_unlock(&c->lock); 189278277Sgonzo} 190278277Sgonzo 191278277Sgonzostatic void 192278277Sgonzo_completion_claim(struct completion *c) 193278277Sgonzo{ 194278277Sgonzo 195278277Sgonzo KASSERT(mtx_owned(&c->lock), 196278277Sgonzo ("_completion_claim should be called with acquired lock")); 197278277Sgonzo KASSERT(c->done != 0, ("_completion_claim on non-waited completion")); 198278277Sgonzo if (c->done > 0) 199278277Sgonzo c->done--; 200278277Sgonzo else 201278277Sgonzo KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done)); 202278277Sgonzo} 203278277Sgonzo 204278277Sgonzovoid 205278277Sgonzowait_for_completion(struct completion *c) 206278277Sgonzo{ 207278277Sgonzo mtx_lock(&c->lock); 208278277Sgonzo if (!c->done) 209278277Sgonzo cv_wait(&c->cv, &c->lock); 210278277Sgonzo c->done--; 211278277Sgonzo mtx_unlock(&c->lock); 212278277Sgonzo} 213278277Sgonzo 214278277Sgonzoint 215278277Sgonzotry_wait_for_completion(struct completion *c) 216278277Sgonzo{ 217278277Sgonzo int res = 0; 218278277Sgonzo 219278277Sgonzo mtx_lock(&c->lock); 220278277Sgonzo if (!c->done) 221278277Sgonzo res = 1; 222278277Sgonzo else 223278277Sgonzo c->done--; 224278277Sgonzo mtx_unlock(&c->lock); 225278277Sgonzo return res == 0; 226278277Sgonzo} 227278277Sgonzo 228278277Sgonzoint 229278277Sgonzowait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout) 230278277Sgonzo{ 231278277Sgonzo int res = 0; 232278277Sgonzo unsigned long start, now; 233278277Sgonzo start = jiffies; 234278277Sgonzo 235278277Sgonzo mtx_lock(&c->lock); 236278277Sgonzo while (c->done == 0) { 237278277Sgonzo res = cv_timedwait_sig(&c->cv, &c->lock, timeout); 238278277Sgonzo if (res) 239278277Sgonzo goto out; 240278277Sgonzo now = jiffies; 241278277Sgonzo if (timeout < (now - start)) { 242278277Sgonzo res = EWOULDBLOCK; 243278277Sgonzo goto out; 244278277Sgonzo } 245278277Sgonzo 246278277Sgonzo timeout -= (now - start); 247278277Sgonzo start = now; 248278277Sgonzo } 249278277Sgonzo 250278277Sgonzo _completion_claim(c); 251278277Sgonzo res = 0; 252278277Sgonzo 253278277Sgonzoout: 254278277Sgonzo mtx_unlock(&c->lock); 255278277Sgonzo 256278277Sgonzo if (res == EWOULDBLOCK) { 257278277Sgonzo return 0; 258278277Sgonzo } else if ((res == EINTR) || (res == ERESTART)) { 259278277Sgonzo return -ERESTART; 260278277Sgonzo } else { 261278277Sgonzo KASSERT((res == 0), ("res = %d", res)); 262278277Sgonzo return timeout; 263278277Sgonzo } 264278277Sgonzo} 265278277Sgonzo 266278277Sgonzoint 267278277Sgonzowait_for_completion_interruptible(struct completion *c) 268278277Sgonzo{ 269278277Sgonzo int res = 0; 270278277Sgonzo 271278277Sgonzo mtx_lock(&c->lock); 272278277Sgonzo while (c->done == 0) { 273278277Sgonzo res = cv_wait_sig(&c->cv, &c->lock); 274278277Sgonzo if (res) 275278277Sgonzo goto out; 276278277Sgonzo } 277278277Sgonzo 278278277Sgonzo _completion_claim(c); 279278277Sgonzo 280278277Sgonzoout: 281278277Sgonzo mtx_unlock(&c->lock); 282278277Sgonzo 283278277Sgonzo if ((res == EINTR) || (res == ERESTART)) 284278277Sgonzo res = -ERESTART; 285278277Sgonzo return res; 286278277Sgonzo} 287278277Sgonzo 288278277Sgonzoint 289278277Sgonzowait_for_completion_killable(struct completion *c) 290278277Sgonzo{ 291278277Sgonzo 292278277Sgonzo return wait_for_completion_interruptible(c); 293278277Sgonzo} 294278277Sgonzo 295278277Sgonzo/* 296278277Sgonzo * Semaphore API 297278277Sgonzo */ 298278277Sgonzo 299278277Sgonzovoid sema_sysinit(void *arg) 300278277Sgonzo{ 301278277Sgonzo struct semaphore *s = arg; 302278277Sgonzo 303278277Sgonzo _sema_init(s, 1); 304278277Sgonzo} 305278277Sgonzo 306278277Sgonzovoid 307278277Sgonzo_sema_init(struct semaphore *s, int value) 308278277Sgonzo{ 309278277Sgonzo bzero(s, sizeof(*s)); 310278277Sgonzo mtx_init(&s->mtx, "sema lock", "VCHIQ sepmaphore backing lock", 311278277Sgonzo MTX_DEF | MTX_NOWITNESS | MTX_QUIET); 312278277Sgonzo cv_init(&s->cv, "sema cv"); 313278277Sgonzo s->value = value; 314278277Sgonzo} 315278277Sgonzo 316278277Sgonzovoid 317278277Sgonzo_sema_destroy(struct semaphore *s) 318278277Sgonzo{ 319278277Sgonzo mtx_destroy(&s->mtx); 320278277Sgonzo cv_destroy(&s->cv); 321278277Sgonzo} 322278277Sgonzo 323278277Sgonzovoid 324278277Sgonzodown(struct semaphore *s) 325278277Sgonzo{ 326278277Sgonzo 327278277Sgonzo mtx_lock(&s->mtx); 328278277Sgonzo while (s->value == 0) { 329278277Sgonzo s->waiters++; 330278277Sgonzo cv_wait(&s->cv, &s->mtx); 331278277Sgonzo s->waiters--; 332278277Sgonzo } 333278277Sgonzo 334278277Sgonzo s->value--; 335278277Sgonzo mtx_unlock(&s->mtx); 336278277Sgonzo} 337278277Sgonzo 338278277Sgonzoint 339278277Sgonzodown_interruptible(struct semaphore *s) 340278277Sgonzo{ 341278277Sgonzo int ret ; 342278277Sgonzo 343278277Sgonzo ret = 0; 344278277Sgonzo 345278277Sgonzo mtx_lock(&s->mtx); 346278277Sgonzo 347278277Sgonzo while (s->value == 0) { 348278277Sgonzo s->waiters++; 349278277Sgonzo ret = cv_wait_sig(&s->cv, &s->mtx); 350278277Sgonzo s->waiters--; 351278277Sgonzo 352278277Sgonzo if (ret == EINTR) { 353278277Sgonzo mtx_unlock(&s->mtx); 354278277Sgonzo return (-EINTR); 355278277Sgonzo } 356278277Sgonzo 357278277Sgonzo if (ret == ERESTART) 358278277Sgonzo continue; 359278277Sgonzo } 360278277Sgonzo 361278277Sgonzo s->value--; 362278277Sgonzo mtx_unlock(&s->mtx); 363278277Sgonzo 364278277Sgonzo return (0); 365278277Sgonzo} 366278277Sgonzo 367278277Sgonzoint 368278277Sgonzodown_trylock(struct semaphore *s) 369278277Sgonzo{ 370278277Sgonzo int ret; 371278277Sgonzo 372278277Sgonzo ret = 0; 373278277Sgonzo 374278277Sgonzo mtx_lock(&s->mtx); 375278277Sgonzo 376278277Sgonzo if (s->value > 0) { 377278277Sgonzo /* Success. */ 378278277Sgonzo s->value--; 379278277Sgonzo ret = 0; 380278277Sgonzo } else { 381278277Sgonzo ret = -EAGAIN; 382278277Sgonzo } 383278277Sgonzo 384278277Sgonzo mtx_unlock(&s->mtx); 385278277Sgonzo 386278277Sgonzo return (ret); 387278277Sgonzo} 388278277Sgonzo 389278277Sgonzovoid 390278277Sgonzoup(struct semaphore *s) 391278277Sgonzo{ 392278277Sgonzo mtx_lock(&s->mtx); 393278277Sgonzo s->value++; 394278277Sgonzo if (s->waiters && s->value > 0) 395278277Sgonzo cv_signal(&s->cv); 396278277Sgonzo 397278277Sgonzo mtx_unlock(&s->mtx); 398278277Sgonzo} 399278277Sgonzo 400278277Sgonzo/* 401278277Sgonzo * Logging API 402278277Sgonzo */ 403278277Sgonzovoid 404278277Sgonzorlprintf(int pps, const char *fmt, ...) 405278277Sgonzo{ 406278277Sgonzo va_list ap; 407278277Sgonzo static struct timeval last_printf; 408278277Sgonzo static int count; 409278277Sgonzo 410278277Sgonzo if (ppsratecheck(&last_printf, &count, pps)) { 411278277Sgonzo va_start(ap, fmt); 412278277Sgonzo vprintf(fmt, ap); 413278277Sgonzo va_end(ap); 414278277Sgonzo } 415278277Sgonzo} 416278277Sgonzo 417278277Sgonzovoid 418278277Sgonzodevice_rlprintf(int pps, device_t dev, const char *fmt, ...) 419278277Sgonzo{ 420278277Sgonzo va_list ap; 421278277Sgonzo static struct timeval last_printf; 422278277Sgonzo static int count; 423278277Sgonzo 424278277Sgonzo if (ppsratecheck(&last_printf, &count, pps)) { 425278277Sgonzo va_start(ap, fmt); 426278277Sgonzo device_print_prettyname(dev); 427278277Sgonzo vprintf(fmt, ap); 428278277Sgonzo va_end(ap); 429278277Sgonzo } 430278277Sgonzo} 431278277Sgonzo 432278277Sgonzo/* 433278277Sgonzo * Signals API 434278277Sgonzo */ 435278277Sgonzo 436278277Sgonzovoid 437278277Sgonzoflush_signals(VCHIQ_THREAD_T thr) 438278277Sgonzo{ 439278277Sgonzo printf("Implement ME: %s\n", __func__); 440278277Sgonzo} 441278277Sgonzo 442278277Sgonzoint 443278277Sgonzofatal_signal_pending(VCHIQ_THREAD_T thr) 444278277Sgonzo{ 445278277Sgonzo printf("Implement ME: %s\n", __func__); 446278277Sgonzo return (0); 447278277Sgonzo} 448278277Sgonzo 449278277Sgonzo/* 450278277Sgonzo * kthread API 451278277Sgonzo */ 452278277Sgonzo 453278277Sgonzo/* 454278277Sgonzo * This is a hack to avoid memory leak 455278277Sgonzo */ 456278277Sgonzo#define MAX_THREAD_DATA_SLOTS 32 457278277Sgonzostatic int thread_data_slot = 0; 458278277Sgonzo 459278277Sgonzostruct thread_data { 460278277Sgonzo void *data; 461278277Sgonzo int (*threadfn)(void *); 462278277Sgonzo}; 463278277Sgonzo 464278277Sgonzostatic struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS]; 465278277Sgonzo 466278277Sgonzostatic void 467278277Sgonzokthread_wrapper(void *data) 468278277Sgonzo{ 469278277Sgonzo struct thread_data *slot; 470278277Sgonzo 471278277Sgonzo slot = data; 472278277Sgonzo slot->threadfn(slot->data); 473278277Sgonzo} 474278277Sgonzo 475278277SgonzoVCHIQ_THREAD_T 476278277Sgonzovchiq_thread_create(int (*threadfn)(void *data), 477278277Sgonzo void *data, 478278277Sgonzo const char namefmt[], ...) 479278277Sgonzo{ 480278277Sgonzo VCHIQ_THREAD_T newp; 481278277Sgonzo va_list ap; 482278277Sgonzo char name[MAXCOMLEN+1]; 483278277Sgonzo struct thread_data *slot; 484278277Sgonzo 485278277Sgonzo if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) { 486278277Sgonzo printf("kthread_create: out of thread data slots\n"); 487278277Sgonzo return (NULL); 488278277Sgonzo } 489278277Sgonzo 490278277Sgonzo slot = &thread_slots[thread_data_slot]; 491278277Sgonzo slot->data = data; 492278277Sgonzo slot->threadfn = threadfn; 493278277Sgonzo 494278277Sgonzo va_start(ap, namefmt); 495278277Sgonzo vsnprintf(name, sizeof(name), namefmt, ap); 496278277Sgonzo va_end(ap); 497278277Sgonzo 498278277Sgonzo newp = NULL; 499278277Sgonzo if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0, 500278277Sgonzo "%s", name) != 0) { 501278277Sgonzo /* Just to be sure */ 502278277Sgonzo newp = NULL; 503278277Sgonzo } 504278277Sgonzo else 505278277Sgonzo thread_data_slot++; 506278277Sgonzo 507278277Sgonzo return newp; 508278277Sgonzo} 509278277Sgonzo 510278277Sgonzovoid 511278277Sgonzoset_user_nice(VCHIQ_THREAD_T thr, int nice) 512278277Sgonzo{ 513278277Sgonzo /* NOOP */ 514278277Sgonzo} 515278277Sgonzo 516278277Sgonzovoid 517278277Sgonzowake_up_process(VCHIQ_THREAD_T thr) 518278277Sgonzo{ 519278277Sgonzo /* NOOP */ 520278277Sgonzo} 521278277Sgonzo 522278277Sgonzovoid 523278277Sgonzobcm_mbox_write(int channel, uint32_t data) 524278277Sgonzo{ 525278277Sgonzo device_t mbox; 526278277Sgonzo 527278277Sgonzo mbox = devclass_get_device(devclass_find("mbox"), 0); 528278277Sgonzo 529278277Sgonzo if (mbox) 530278277Sgonzo MBOX_WRITE(mbox, channel, data); 531278277Sgonzo} 532