xref: /freebsd/sys/contrib/vchiq/interface/compat/vchi_bsd.c (revision e453e498cbb88570a3ff7b3679de65c88707da95)
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/stdarg.h>
40 #include <sys/syscallsubr.h>
41 #include <sys/systm.h>
42 #include <sys/taskqueue.h>
43 
44 #include "mbox_if.h"
45 
46 #include <interface/compat/vchi_bsd.h>
47 
48 MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");
49 
50 /*
51  * Timer API
52  */
53 static void
run_timer(void * arg)54 run_timer(void *arg)
55 {
56 	struct timer_list *t = (struct timer_list *) arg;
57 	void (*function)(unsigned long);
58 
59 	mtx_lock_spin(&t->mtx);
60 	if (callout_pending(&t->callout)) {
61 		/* callout was reset */
62 		mtx_unlock_spin(&t->mtx);
63 		return;
64 	}
65 	if (!callout_active(&t->callout)) {
66 		/* callout was stopped */
67 		mtx_unlock_spin(&t->mtx);
68 		return;
69 	}
70 	callout_deactivate(&t->callout);
71 
72 	function = t->function;
73 	mtx_unlock_spin(&t->mtx);
74 
75 	function(t->data);
76 }
77 
78 void
vchiq_init_timer(struct timer_list * t)79 vchiq_init_timer(struct timer_list *t)
80 {
81 	mtx_init(&t->mtx, "dahdi timer lock", NULL, MTX_SPIN);
82 	callout_init(&t->callout, 1);
83 	t->expires = 0;
84 	/*
85 	 * function and data are not initialized intentionally:
86 	 * they are not initialized by Linux implementation too
87 	 */
88 }
89 
90 void
vchiq_setup_timer(struct timer_list * t,void (* function)(unsigned long),unsigned long data)91 vchiq_setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data)
92 {
93 	t->function = function;
94 	t->data = data;
95 	vchiq_init_timer(t);
96 }
97 
98 void
vchiq_mod_timer(struct timer_list * t,unsigned long expires)99 vchiq_mod_timer(struct timer_list *t, unsigned long expires)
100 {
101 	mtx_lock_spin(&t->mtx);
102 	callout_reset(&t->callout, expires - jiffies, run_timer, t);
103 	mtx_unlock_spin(&t->mtx);
104 }
105 
106 void
vchiq_add_timer(struct timer_list * t)107 vchiq_add_timer(struct timer_list *t)
108 {
109 	vchiq_mod_timer(t, t->expires);
110 }
111 
112 int
vchiq_del_timer_sync(struct timer_list * t)113 vchiq_del_timer_sync(struct timer_list *t)
114 {
115 	mtx_lock_spin(&t->mtx);
116 	callout_stop(&t->callout);
117 	mtx_unlock_spin(&t->mtx);
118 
119 	mtx_destroy(&t->mtx);
120 	return 0;
121 }
122 
123 int
vchiq_del_timer(struct timer_list * t)124 vchiq_del_timer(struct timer_list *t)
125 {
126 	vchiq_del_timer_sync(t);
127 	return 0;
128 }
129 
130 /*
131  * Completion API
132  */
133 void
init_completion(struct completion * c)134 init_completion(struct completion *c)
135 {
136 	cv_init(&c->cv, "VCHI completion cv");
137 	mtx_init(&c->lock, "VCHI completion lock", "condvar", MTX_DEF);
138 	c->done = 0;
139 }
140 
141 void
destroy_completion(struct completion * c)142 destroy_completion(struct completion *c)
143 {
144 	cv_destroy(&c->cv);
145 	mtx_destroy(&c->lock);
146 }
147 
148 void
complete(struct completion * c)149 complete(struct completion *c)
150 {
151 	mtx_lock(&c->lock);
152 
153 	if (c->done >= 0) {
154 		KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */
155 		c->done++;
156 		cv_signal(&c->cv);
157 	} else {
158 		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
159 	}
160 
161 	mtx_unlock(&c->lock);
162 }
163 
164 void
complete_all(struct completion * c)165 complete_all(struct completion *c)
166 {
167 	mtx_lock(&c->lock);
168 
169 	if (c->done >= 0) {
170 		KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */
171 		c->done = -1;
172 		cv_broadcast(&c->cv);
173 	} else {
174 		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
175 	}
176 
177 	mtx_unlock(&c->lock);
178 }
179 
180 void
INIT_COMPLETION_locked(struct completion * c)181 INIT_COMPLETION_locked(struct completion *c)
182 {
183 	mtx_lock(&c->lock);
184 
185 	c->done = 0;
186 
187 	mtx_unlock(&c->lock);
188 }
189 
190 static void
_completion_claim(struct completion * c)191 _completion_claim(struct completion *c)
192 {
193 
194 	KASSERT(mtx_owned(&c->lock),
195 	    ("_completion_claim should be called with acquired lock"));
196 	KASSERT(c->done != 0, ("_completion_claim on non-waited completion"));
197 	if (c->done > 0)
198 		c->done--;
199 	else
200 		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
201 }
202 
203 void
wait_for_completion(struct completion * c)204 wait_for_completion(struct completion *c)
205 {
206 	mtx_lock(&c->lock);
207 	if (!c->done)
208 		cv_wait(&c->cv, &c->lock);
209 	c->done--;
210 	mtx_unlock(&c->lock);
211 }
212 
213 int
try_wait_for_completion(struct completion * c)214 try_wait_for_completion(struct completion *c)
215 {
216 	int res = 0;
217 
218 	mtx_lock(&c->lock);
219 	if (!c->done)
220 		res = 1;
221 	else
222 		c->done--;
223 	mtx_unlock(&c->lock);
224 	return res == 0;
225 }
226 
227 int
wait_for_completion_interruptible_timeout(struct completion * c,unsigned long timeout)228 wait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout)
229 {
230 	int res = 0;
231 	unsigned long start, now;
232 	start = jiffies;
233 
234 	mtx_lock(&c->lock);
235 	while (c->done == 0) {
236 		res = cv_timedwait_sig(&c->cv, &c->lock, timeout);
237 		if (res)
238 			goto out;
239 		now = jiffies;
240 		if (timeout < (now - start)) {
241 			res = EWOULDBLOCK;
242 			goto out;
243 		}
244 
245 		timeout -= (now - start);
246 		start = now;
247 	}
248 
249 	_completion_claim(c);
250 	res = 0;
251 
252 out:
253 	mtx_unlock(&c->lock);
254 
255 	if (res == EWOULDBLOCK) {
256 		return 0;
257 	} else if ((res == EINTR) || (res == ERESTART)) {
258 		return -ERESTART;
259 	} else {
260 		KASSERT((res == 0), ("res = %d", res));
261 		return timeout;
262 	}
263 }
264 
265 int
wait_for_completion_interruptible(struct completion * c)266 wait_for_completion_interruptible(struct completion *c)
267 {
268 	int res = 0;
269 
270 	mtx_lock(&c->lock);
271 	while (c->done == 0) {
272 		res = cv_wait_sig(&c->cv, &c->lock);
273 		if (res)
274 			goto out;
275 	}
276 
277 	_completion_claim(c);
278 
279 out:
280 	mtx_unlock(&c->lock);
281 
282 	if ((res == EINTR) || (res == ERESTART))
283 		res = -ERESTART;
284 	return res;
285 }
286 
287 int
wait_for_completion_killable(struct completion * c)288 wait_for_completion_killable(struct completion *c)
289 {
290 
291 	return wait_for_completion_interruptible(c);
292 }
293 
294 /*
295  * Semaphore API
296  */
297 
sema_sysinit(void * arg)298 void sema_sysinit(void *arg)
299 {
300 	struct semaphore *s = arg;
301 
302 	_sema_init(s, 1);
303 }
304 
305 void
_sema_init(struct semaphore * s,int value)306 _sema_init(struct semaphore *s, int value)
307 {
308 	bzero(s, sizeof(*s));
309 	mtx_init(&s->mtx, "sema lock", "VCHIQ sepmaphore backing lock",
310 		MTX_DEF | MTX_NOWITNESS | MTX_QUIET);
311 	cv_init(&s->cv, "sema cv");
312 	s->value = value;
313 }
314 
315 void
_sema_destroy(struct semaphore * s)316 _sema_destroy(struct semaphore *s)
317 {
318 	mtx_destroy(&s->mtx);
319 	cv_destroy(&s->cv);
320 }
321 
322 void
down(struct semaphore * s)323 down(struct semaphore *s)
324 {
325 
326 	mtx_lock(&s->mtx);
327 	while (s->value == 0) {
328 		s->waiters++;
329 		cv_wait(&s->cv, &s->mtx);
330 		s->waiters--;
331 	}
332 
333 	s->value--;
334 	mtx_unlock(&s->mtx);
335 }
336 
337 int
down_interruptible(struct semaphore * s)338 down_interruptible(struct semaphore *s)
339 {
340 	int ret ;
341 
342 	ret = 0;
343 
344 	mtx_lock(&s->mtx);
345 
346 	while (s->value == 0) {
347 		s->waiters++;
348 		ret = cv_wait_sig(&s->cv, &s->mtx);
349 		s->waiters--;
350 
351 		if (ret == EINTR) {
352 			mtx_unlock(&s->mtx);
353 			return (-EINTR);
354 		}
355 
356 		if (ret == ERESTART)
357 			continue;
358 	}
359 
360 	s->value--;
361 	mtx_unlock(&s->mtx);
362 
363 	return (0);
364 }
365 
366 int
down_trylock(struct semaphore * s)367 down_trylock(struct semaphore *s)
368 {
369 	int ret;
370 
371 	ret = 0;
372 
373 	mtx_lock(&s->mtx);
374 
375 	if (s->value > 0) {
376 		/* Success. */
377 		s->value--;
378 		ret = 0;
379 	} else {
380 		ret = -EAGAIN;
381 	}
382 
383 	mtx_unlock(&s->mtx);
384 
385 	return (ret);
386 }
387 
388 void
up(struct semaphore * s)389 up(struct semaphore *s)
390 {
391 	mtx_lock(&s->mtx);
392 	s->value++;
393 	if (s->waiters && s->value > 0)
394 		cv_signal(&s->cv);
395 
396 	mtx_unlock(&s->mtx);
397 }
398 
399 /*
400  * Logging API
401  */
402 void
rlprintf(int pps,const char * fmt,...)403 rlprintf(int pps, const char *fmt, ...)
404 {
405 	va_list ap;
406 	static struct timeval last_printf;
407 	static int count;
408 
409 	if (ppsratecheck(&last_printf, &count, pps)) {
410 		va_start(ap, fmt);
411 		vprintf(fmt, ap);
412 		va_end(ap);
413 	}
414 }
415 
416 void
device_rlprintf(int pps,device_t dev,const char * fmt,...)417 device_rlprintf(int pps, device_t dev, const char *fmt, ...)
418 {
419 	va_list ap;
420 	static struct timeval last_printf;
421 	static int count;
422 
423 	if (ppsratecheck(&last_printf, &count, pps)) {
424 		va_start(ap, fmt);
425 		device_print_prettyname(dev);
426 		vprintf(fmt, ap);
427 		va_end(ap);
428 	}
429 }
430 
431 /*
432  * Signals API
433  */
434 
435 void
flush_signals(VCHIQ_THREAD_T thr)436 flush_signals(VCHIQ_THREAD_T thr)
437 {
438 	printf("Implement ME: %s\n", __func__);
439 }
440 
441 int
fatal_signal_pending(VCHIQ_THREAD_T thr)442 fatal_signal_pending(VCHIQ_THREAD_T thr)
443 {
444 	printf("Implement ME: %s\n", __func__);
445 	return (0);
446 }
447 
448 /*
449  * kthread API
450  */
451 
452 /*
453  *  This is a hack to avoid memory leak
454  */
455 #define MAX_THREAD_DATA_SLOTS	32
456 static int thread_data_slot = 0;
457 
458 struct thread_data {
459 	void *data;
460 	int (*threadfn)(void *);
461 };
462 
463 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
464 
465 static void
kthread_wrapper(void * data)466 kthread_wrapper(void *data)
467 {
468 	struct thread_data *slot;
469 
470 	slot = data;
471 	slot->threadfn(slot->data);
472 }
473 
474 VCHIQ_THREAD_T
vchiq_thread_create(int (* threadfn)(void * data),void * data,const char namefmt[],...)475 vchiq_thread_create(int (*threadfn)(void *data),
476 	void *data,
477 	const char namefmt[], ...)
478 {
479 	VCHIQ_THREAD_T newp;
480 	va_list ap;
481 	char name[MAXCOMLEN+1];
482 	struct thread_data *slot;
483 
484 	if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) {
485 		printf("kthread_create: out of thread data slots\n");
486 		return (NULL);
487 	}
488 
489 	slot = &thread_slots[thread_data_slot];
490 	slot->data = data;
491 	slot->threadfn = threadfn;
492 
493 	va_start(ap, namefmt);
494 	vsnprintf(name, sizeof(name), namefmt, ap);
495 	va_end(ap);
496 
497 	newp = NULL;
498 	if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0,
499 	    "%s", name) != 0) {
500 		/* Just to be sure */
501 		newp = NULL;
502 	}
503 	else
504 		thread_data_slot++;
505 
506 	return newp;
507 }
508 
509 void
set_user_nice(VCHIQ_THREAD_T thr,int nice)510 set_user_nice(VCHIQ_THREAD_T thr, int nice)
511 {
512 	/* NOOP */
513 }
514 
515 void
wake_up_process(VCHIQ_THREAD_T thr)516 wake_up_process(VCHIQ_THREAD_T thr)
517 {
518 	/* NOOP */
519 }
520 
521 void
bcm_mbox_write(int channel,uint32_t data)522 bcm_mbox_write(int channel, uint32_t data)
523 {
524 	device_t mbox;
525 
526         mbox = devclass_get_device(devclass_find("mbox"), 0);
527 
528         if (mbox)
529                 MBOX_WRITE(mbox, channel, data);
530 }
531