Path: blob/main/sys/contrib/vchiq/interface/compat/vchi_bsd.c
48383 views
/*-1* Copyright (c) 2010 Max Khon <[email protected]>2* All rights reserved.3*4* This software was developed by Max Khon under sponsorship from5* the FreeBSD Foundation and Ethon Technologies GmbH.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*28* $Id: bsd-compat.c 9253 2010-09-02 10:12:09Z fjoe $29*/3031#include <sys/types.h>32#include <sys/limits.h>33#include <sys/bus.h>34#include <sys/callout.h>35#include <sys/firmware.h>36#include <sys/param.h>37#include <sys/proc.h>38#include <sys/stdarg.h>39#include <sys/syscallsubr.h>40#include <sys/systm.h>41#include <sys/taskqueue.h>4243#include "mbox_if.h"4445#include <interface/compat/vchi_bsd.h>4647MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");4849/*50* Timer API51*/52static void53run_timer(void *arg)54{55struct timer_list *t = (struct timer_list *) arg;56void (*function)(unsigned long);5758mtx_lock_spin(&t->mtx);59if (callout_pending(&t->callout)) {60/* callout was reset */61mtx_unlock_spin(&t->mtx);62return;63}64if (!callout_active(&t->callout)) {65/* callout was stopped */66mtx_unlock_spin(&t->mtx);67return;68}69callout_deactivate(&t->callout);7071function = t->function;72mtx_unlock_spin(&t->mtx);7374function(t->data);75}7677void78vchiq_init_timer(struct timer_list *t)79{80mtx_init(&t->mtx, "dahdi timer lock", NULL, MTX_SPIN);81callout_init(&t->callout, 1);82t->expires = 0;83/*84* function and data are not initialized intentionally:85* they are not initialized by Linux implementation too86*/87}8889void90vchiq_setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data)91{92t->function = function;93t->data = data;94vchiq_init_timer(t);95}9697void98vchiq_mod_timer(struct timer_list *t, unsigned long expires)99{100mtx_lock_spin(&t->mtx);101callout_reset(&t->callout, expires - jiffies, run_timer, t);102mtx_unlock_spin(&t->mtx);103}104105void106vchiq_add_timer(struct timer_list *t)107{108vchiq_mod_timer(t, t->expires);109}110111int112vchiq_del_timer_sync(struct timer_list *t)113{114mtx_lock_spin(&t->mtx);115callout_stop(&t->callout);116mtx_unlock_spin(&t->mtx);117118mtx_destroy(&t->mtx);119return 0;120}121122int123vchiq_del_timer(struct timer_list *t)124{125vchiq_del_timer_sync(t);126return 0;127}128129/*130* Completion API131*/132void133init_completion(struct completion *c)134{135cv_init(&c->cv, "VCHI completion cv");136mtx_init(&c->lock, "VCHI completion lock", "condvar", MTX_DEF);137c->done = 0;138}139140void141destroy_completion(struct completion *c)142{143cv_destroy(&c->cv);144mtx_destroy(&c->lock);145}146147void148complete(struct completion *c)149{150mtx_lock(&c->lock);151152if (c->done >= 0) {153KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */154c->done++;155cv_signal(&c->cv);156} else {157KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));158}159160mtx_unlock(&c->lock);161}162163void164complete_all(struct completion *c)165{166mtx_lock(&c->lock);167168if (c->done >= 0) {169KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */170c->done = -1;171cv_broadcast(&c->cv);172} else {173KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));174}175176mtx_unlock(&c->lock);177}178179void180INIT_COMPLETION_locked(struct completion *c)181{182mtx_lock(&c->lock);183184c->done = 0;185186mtx_unlock(&c->lock);187}188189static void190_completion_claim(struct completion *c)191{192193KASSERT(mtx_owned(&c->lock),194("_completion_claim should be called with acquired lock"));195KASSERT(c->done != 0, ("_completion_claim on non-waited completion"));196if (c->done > 0)197c->done--;198else199KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));200}201202void203wait_for_completion(struct completion *c)204{205mtx_lock(&c->lock);206if (!c->done)207cv_wait(&c->cv, &c->lock);208c->done--;209mtx_unlock(&c->lock);210}211212int213try_wait_for_completion(struct completion *c)214{215int res = 0;216217mtx_lock(&c->lock);218if (!c->done)219res = 1;220else221c->done--;222mtx_unlock(&c->lock);223return res == 0;224}225226int227wait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout)228{229int res = 0;230unsigned long start, now;231start = jiffies;232233mtx_lock(&c->lock);234while (c->done == 0) {235res = cv_timedwait_sig(&c->cv, &c->lock, timeout);236if (res)237goto out;238now = jiffies;239if (timeout < (now - start)) {240res = EWOULDBLOCK;241goto out;242}243244timeout -= (now - start);245start = now;246}247248_completion_claim(c);249res = 0;250251out:252mtx_unlock(&c->lock);253254if (res == EWOULDBLOCK) {255return 0;256} else if ((res == EINTR) || (res == ERESTART)) {257return -ERESTART;258} else {259KASSERT((res == 0), ("res = %d", res));260return timeout;261}262}263264int265wait_for_completion_interruptible(struct completion *c)266{267int res = 0;268269mtx_lock(&c->lock);270while (c->done == 0) {271res = cv_wait_sig(&c->cv, &c->lock);272if (res)273goto out;274}275276_completion_claim(c);277278out:279mtx_unlock(&c->lock);280281if ((res == EINTR) || (res == ERESTART))282res = -ERESTART;283return res;284}285286int287wait_for_completion_killable(struct completion *c)288{289290return wait_for_completion_interruptible(c);291}292293/*294* Semaphore API295*/296297void sema_sysinit(void *arg)298{299struct semaphore *s = arg;300301_sema_init(s, 1);302}303304void305_sema_init(struct semaphore *s, int value)306{307bzero(s, sizeof(*s));308mtx_init(&s->mtx, "sema lock", "VCHIQ sepmaphore backing lock",309MTX_DEF | MTX_NOWITNESS | MTX_QUIET);310cv_init(&s->cv, "sema cv");311s->value = value;312}313314void315_sema_destroy(struct semaphore *s)316{317mtx_destroy(&s->mtx);318cv_destroy(&s->cv);319}320321void322down(struct semaphore *s)323{324325mtx_lock(&s->mtx);326while (s->value == 0) {327s->waiters++;328cv_wait(&s->cv, &s->mtx);329s->waiters--;330}331332s->value--;333mtx_unlock(&s->mtx);334}335336int337down_interruptible(struct semaphore *s)338{339int ret ;340341ret = 0;342343mtx_lock(&s->mtx);344345while (s->value == 0) {346s->waiters++;347ret = cv_wait_sig(&s->cv, &s->mtx);348s->waiters--;349350if (ret == EINTR) {351mtx_unlock(&s->mtx);352return (-EINTR);353}354355if (ret == ERESTART)356continue;357}358359s->value--;360mtx_unlock(&s->mtx);361362return (0);363}364365int366down_trylock(struct semaphore *s)367{368int ret;369370ret = 0;371372mtx_lock(&s->mtx);373374if (s->value > 0) {375/* Success. */376s->value--;377ret = 0;378} else {379ret = -EAGAIN;380}381382mtx_unlock(&s->mtx);383384return (ret);385}386387void388up(struct semaphore *s)389{390mtx_lock(&s->mtx);391s->value++;392if (s->waiters && s->value > 0)393cv_signal(&s->cv);394395mtx_unlock(&s->mtx);396}397398/*399* Logging API400*/401void402rlprintf(int pps, const char *fmt, ...)403{404va_list ap;405static struct timeval last_printf;406static int count;407408if (ppsratecheck(&last_printf, &count, pps)) {409va_start(ap, fmt);410vprintf(fmt, ap);411va_end(ap);412}413}414415void416device_rlprintf(int pps, device_t dev, const char *fmt, ...)417{418va_list ap;419static struct timeval last_printf;420static int count;421422if (ppsratecheck(&last_printf, &count, pps)) {423va_start(ap, fmt);424device_print_prettyname(dev);425vprintf(fmt, ap);426va_end(ap);427}428}429430/*431* Signals API432*/433434void435flush_signals(VCHIQ_THREAD_T thr)436{437printf("Implement ME: %s\n", __func__);438}439440int441fatal_signal_pending(VCHIQ_THREAD_T thr)442{443printf("Implement ME: %s\n", __func__);444return (0);445}446447/*448* kthread API449*/450451/*452* This is a hack to avoid memory leak453*/454#define MAX_THREAD_DATA_SLOTS 32455static int thread_data_slot = 0;456457struct thread_data {458void *data;459int (*threadfn)(void *);460};461462static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];463464static void465kthread_wrapper(void *data)466{467struct thread_data *slot;468469slot = data;470slot->threadfn(slot->data);471}472473VCHIQ_THREAD_T474vchiq_thread_create(int (*threadfn)(void *data),475void *data,476const char namefmt[], ...)477{478VCHIQ_THREAD_T newp;479va_list ap;480char name[MAXCOMLEN+1];481struct thread_data *slot;482483if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) {484printf("kthread_create: out of thread data slots\n");485return (NULL);486}487488slot = &thread_slots[thread_data_slot];489slot->data = data;490slot->threadfn = threadfn;491492va_start(ap, namefmt);493vsnprintf(name, sizeof(name), namefmt, ap);494va_end(ap);495496newp = NULL;497if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0,498"%s", name) != 0) {499/* Just to be sure */500newp = NULL;501}502else503thread_data_slot++;504505return newp;506}507508void509set_user_nice(VCHIQ_THREAD_T thr, int nice)510{511/* NOOP */512}513514void515wake_up_process(VCHIQ_THREAD_T thr)516{517/* NOOP */518}519520void521bcm_mbox_write(int channel, uint32_t data)522{523device_t mbox;524525mbox = devclass_get_device(devclass_find("mbox"), 0);526527if (mbox)528MBOX_WRITE(mbox, channel, data);529}530531532