xref: /freebsd/sys/contrib/vchiq/interface/compat/vchi_bsd.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
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 
49 MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");
50 
51 /*
52  * Timer API
53  */
54 static void
55 run_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 
79 void
80 init_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 
91 void
92 setup_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 
99 void
100 mod_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 
107 void
108 add_timer(struct timer_list *t)
109 {
110 	mod_timer(t, t->expires);
111 }
112 
113 int
114 del_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 
124 int
125 del_timer(struct timer_list *t)
126 {
127 	del_timer_sync(t);
128 	return 0;
129 }
130 
131 /*
132  * Completion API
133  */
134 void
135 init_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 
142 void
143 destroy_completion(struct completion *c)
144 {
145 	cv_destroy(&c->cv);
146 	mtx_destroy(&c->lock);
147 }
148 
149 void
150 complete(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 
165 void
166 complete_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 
181 void
182 INIT_COMPLETION_locked(struct completion *c)
183 {
184 	mtx_lock(&c->lock);
185 
186 	c->done = 0;
187 
188 	mtx_unlock(&c->lock);
189 }
190 
191 static 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 
204 void
205 wait_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 
214 int
215 try_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 
228 int
229 wait_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 
253 out:
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 
266 int
267 wait_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 
280 out:
281 	mtx_unlock(&c->lock);
282 
283 	if ((res == EINTR) || (res == ERESTART))
284 		res = -ERESTART;
285 	return res;
286 }
287 
288 int
289 wait_for_completion_killable(struct completion *c)
290 {
291 
292 	return wait_for_completion_interruptible(c);
293 }
294 
295 /*
296  * Semaphore API
297  */
298 
299 void sema_sysinit(void *arg)
300 {
301 	struct semaphore *s = arg;
302 
303 	printf("sema_sysinit\n");
304 	_sema_init(s, 1);
305 }
306 
307 void
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 
317 void
318 _sema_destroy(struct semaphore *s)
319 {
320 	mtx_destroy(&s->mtx);
321 	cv_destroy(&s->cv);
322 }
323 
324 void
325 down(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 
339 int
340 down_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 
368 int
369 down_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 
390 void
391 up(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  */
404 void
405 rlprintf(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 
418 void
419 device_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 
437 void
438 flush_signals(VCHIQ_THREAD_T thr)
439 {
440 	printf("Implement ME: %s\n", __func__);
441 }
442 
443 int
444 fatal_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
458 static int thread_data_slot = 0;
459 
460 struct thread_data {
461 	void *data;
462 	int (*threadfn)(void *);
463 };
464 
465 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
466 
467 static void
468 kthread_wrapper(void *data)
469 {
470 	struct thread_data *slot;
471 
472 	slot = data;
473 	slot->threadfn(slot->data);
474 }
475 
476 VCHIQ_THREAD_T
477 vchiq_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 
511 void
512 set_user_nice(VCHIQ_THREAD_T thr, int nice)
513 {
514 	/* NOOP */
515 }
516 
517 void
518 wake_up_process(VCHIQ_THREAD_T thr)
519 {
520 	/* NOOP */
521 }
522 
523 void
524 bcm_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