Home | History | Annotate | Line # | Download | only in compat
      1 /*-
      2  * Copyright (c) 2010 Max Khon <fjoe (at) 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: vchi_bsd.c,v 1.10 2017/11/05 09:11:43 skrll Exp $
     30  */
     31 
     32 #include <sys/types.h>
     33 #include <sys/bus.h>
     34 #include <sys/callout.h>
     35 #include <sys/param.h>
     36 #include <sys/proc.h>
     37 #include <sys/systm.h>
     38 
     39 #include <interface/compat/vchi_bsd.h>
     40 
     41 MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");
     42 
     43 /*
     44  * Timer API
     45  */
     46 static void
     47 run_timer(void *arg)
     48 {
     49 	struct timer_list *t = (struct timer_list *) arg;
     50 	void (*function)(unsigned long);
     51 
     52 	spin_lock(&t->mtx);
     53 	if (callout_pending(&t->callout)) {
     54 		/* callout was reset */
     55 		spin_unlock(&t->mtx);
     56 		return;
     57 	}
     58 	if (!callout_active(&t->callout)) {
     59 		/* callout was stopped */
     60 		spin_unlock(&t->mtx);
     61 		return;
     62 	}
     63 	callout_ack(&t->callout);
     64 
     65 	function = t->function;
     66 	spin_unlock(&t->mtx);
     67 
     68 	function(t->data);
     69 }
     70 
     71 void
     72 init_timer(struct timer_list *t)
     73 {
     74 	spin_lock_init(&t->mtx);
     75 	callout_init(&t->callout, CALLOUT_MPSAFE);
     76 	t->expires = 0;
     77 	/*
     78 	 * function and data are not initialized intentionally:
     79 	 * they are not initialized by Linux implementation too
     80 	 */
     81 }
     82 
     83 void
     84 setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data)
     85 {
     86 	t->function = function;
     87 	t->data = data;
     88 	init_timer(t);
     89 }
     90 
     91 void
     92 mod_timer(struct timer_list *t, unsigned long expires)
     93 {
     94 	spin_lock(&t->mtx);
     95 	callout_reset(&t->callout, expires - jiffies, run_timer, t);
     96 	spin_unlock(&t->mtx);
     97 }
     98 
     99 void
    100 add_timer(struct timer_list *t)
    101 {
    102 	mod_timer(t, t->expires);
    103 }
    104 
    105 int
    106 del_timer_sync(struct timer_list *t)
    107 {
    108 	spin_lock(&t->mtx);
    109 	callout_halt(&t->callout, &t->mtx);
    110 	spin_unlock(&t->mtx);
    111 
    112 	spin_lock_destroy(&t->mtx);
    113 	return 0;
    114 }
    115 
    116 int
    117 del_timer(struct timer_list *t)
    118 {
    119 	del_timer_sync(t);
    120 	return 0;
    121 }
    122 
    123 /*
    124  * Semaphore API
    125  */
    126 
    127 void sema_sysinit(void *arg)
    128 {
    129 	struct semaphore *s = arg;
    130 
    131 	printf("sema_sysinit\n");
    132 	_sema_init(s, 1);
    133 }
    134 
    135 void
    136 _sema_init(struct semaphore *s, int value)
    137 {
    138 	memset(s, 0, sizeof(*s));
    139 	mutex_init(&s->mtx, MUTEX_DEFAULT, IPL_VM);
    140 	cv_init(&s->cv, "semacv");
    141 	s->value = value;
    142 }
    143 
    144 void
    145 _sema_destroy(struct semaphore *s)
    146 {
    147 	mutex_destroy(&s->mtx);
    148 	cv_destroy(&s->cv);
    149 }
    150 
    151 void
    152 down(struct semaphore *s)
    153 {
    154 
    155 	mutex_enter(&s->mtx);
    156 	while (s->value == 0) {
    157 		s->waiters++;
    158 		cv_wait(&s->cv, &s->mtx);
    159 		s->waiters--;
    160 	}
    161 
    162 	s->value--;
    163 	mutex_exit(&s->mtx);
    164 }
    165 
    166 int
    167 down_interruptible(struct semaphore *s)
    168 {
    169 
    170 	mutex_enter(&s->mtx);
    171 
    172 	while (s->value == 0) {
    173 		s->waiters++;
    174 		int ret = cv_wait_sig(&s->cv, &s->mtx);
    175 		s->waiters--;
    176 
    177 		if (ret == EINTR || ret == ERESTART) {
    178 			mutex_exit(&s->mtx);
    179 			return -EINTR;
    180 		}
    181 	}
    182 
    183 	s->value--;
    184 	mutex_exit(&s->mtx);
    185 
    186 	return 0;
    187 }
    188 
    189 int
    190 down_trylock(struct semaphore *s)
    191 {
    192 	int ret = 1;
    193 
    194 	mutex_enter(&s->mtx);
    195 
    196 	if (s->value > 0) {
    197 		/* Success. */
    198 		s->value--;
    199 		ret = 0;
    200 	}
    201 
    202 	mutex_exit(&s->mtx);
    203 
    204 	return ret;
    205 }
    206 
    207 void
    208 up(struct semaphore *s)
    209 {
    210 	mutex_enter(&s->mtx);
    211 	s->value++;
    212 	if (s->value > 0 && s->waiters)
    213 		cv_signal(&s->cv);
    214 
    215 	mutex_exit(&s->mtx);
    216 }
    217 
    218 /*
    219  * Logging API
    220  */
    221 void
    222 rlprintf(int pps, const char *fmt, ...)
    223 {
    224 	va_list ap;
    225 	static struct timeval last_printf;
    226 	static int count;
    227 
    228 	if (ppsratecheck(&last_printf, &count, pps)) {
    229 		va_start(ap, fmt);
    230 		vprintf(fmt, ap);
    231 		va_end(ap);
    232 	}
    233 }
    234 
    235 void
    236 device_rlprintf(int pps, device_t dev, const char *fmt, ...)
    237 {
    238 	va_list ap;
    239 	static struct timeval last_printf;
    240 	static int count;
    241 
    242 	if (ppsratecheck(&last_printf, &count, pps)) {
    243 		va_start(ap, fmt);
    244 		device_print_prettyname(dev);
    245 		vprintf(fmt, ap);
    246 		va_end(ap);
    247 	}
    248 }
    249 
    250 /*
    251  * Signals API
    252  */
    253 
    254 void
    255 flush_signals(VCHIQ_THREAD_T thr)
    256 {
    257 	printf("Implement ME: %s\n", __func__);
    258 }
    259 
    260 int
    261 fatal_signal_pending(VCHIQ_THREAD_T thr)
    262 {
    263 	printf("Implement ME: %s\n", __func__);
    264 	return 0;
    265 }
    266 
    267 /*
    268  * kthread API
    269  */
    270 
    271 /*
    272  *  This is a hack to avoid memory leak
    273  */
    274 #define MAX_THREAD_DATA_SLOTS	32
    275 static int thread_data_slot = 0;
    276 
    277 struct thread_data {
    278 	void *data;
    279 	int (*threadfn)(void *);
    280 };
    281 
    282 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
    283 
    284 static void
    285 kthread_wrapper(void *data)
    286 {
    287 	struct thread_data *slot;
    288 
    289 	slot = data;
    290 	slot->threadfn(slot->data);
    291 }
    292 
    293 VCHIQ_THREAD_T
    294 vchiq_thread_create(int (*threadfn)(void *data),
    295 	void *data,
    296 	const char namefmt[], ...)
    297 {
    298 	VCHIQ_THREAD_T newt;
    299 	va_list ap;
    300 	char name[MAXCOMLEN+1];
    301 	struct thread_data *slot;
    302 
    303 	if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) {
    304 		printf("kthread_create: out of thread data slots\n");
    305 		return NULL;
    306 	}
    307 
    308 	slot = &thread_slots[thread_data_slot];
    309 	slot->data = data;
    310 	slot->threadfn = threadfn;
    311 
    312 	va_start(ap, namefmt);
    313 	vsnprintf(name, sizeof(name), namefmt, ap);
    314 	va_end(ap);
    315 
    316 	newt = NULL;
    317 	if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, kthread_wrapper,
    318 	    slot, &newt, "%s", name) != 0) {
    319 		/* Just to be sure */
    320 		newt = NULL;
    321 	} else {
    322 		thread_data_slot++;
    323 	}
    324 
    325 	return newt;
    326 }
    327 
    328 void
    329 set_user_nice(VCHIQ_THREAD_T thr, int nice)
    330 {
    331 	/* NOOP */
    332 }
    333 
    334 void
    335 wake_up_process(VCHIQ_THREAD_T thr)
    336 {
    337 	/* NOOP */
    338 }
    339