vchi_bsd.c revision 283291
1291716Sken/*-
2291716Sken * Copyright (c) 2010 Max Khon <fjoe@freebsd.org>
3291716Sken * All rights reserved.
4291716Sken *
5291716Sken * This software was developed by Max Khon under sponsorship from
6291716Sken * the FreeBSD Foundation and Ethon Technologies GmbH.
7291716Sken *
8291716Sken * Redistribution and use in source and binary forms, with or without
9291716Sken * modification, are permitted provided that the following conditions
10291716Sken * are met:
11291716Sken * 1. Redistributions of source code must retain the above copyright
12291716Sken *    notice, this list of conditions and the following disclaimer.
13291716Sken * 2. Redistributions in binary form must reproduce the above copyright
14291716Sken *    notice, this list of conditions and the following disclaimer in the
15291716Sken *    documentation and/or other materials provided with the distribution.
16291716Sken *
17291716Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18291716Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19291716Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20291716Sken * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21291716Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22291716Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23291716Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24291716Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25291716Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26291716Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27291716Sken * SUCH DAMAGE.
28291716Sken *
29291716Sken * $Id: bsd-compat.c 9253 2010-09-02 10:12:09Z fjoe $
30291716Sken */
31291716Sken
32291716Sken#include <sys/types.h>
33291716Sken#include <sys/limits.h>
34291716Sken#include <sys/bus.h>
35291716Sken#include <sys/callout.h>
36291716Sken#include <sys/firmware.h>
37291716Sken#include <sys/param.h>
38291716Sken#include <sys/proc.h>
39291716Sken#include <sys/syscallsubr.h>
40291716Sken#include <sys/systm.h>
41291716Sken#include <sys/taskqueue.h>
42291716Sken
43291716Sken#include <machine/stdarg.h>
44291716Sken
45291716Sken#include "mbox_if.h"
46291716Sken
47291716Sken#include <interface/compat/vchi_bsd.h>
48291716Sken
49291716SkenMALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");
50291716Sken
51291716Sken/*
52291716Sken * Timer API
53291716Sken */
54291716Skenstatic void
55291716Skenrun_timer(void *arg)
56291716Sken{
57291716Sken	struct timer_list *t = (struct timer_list *) arg;
58291716Sken	void (*function)(unsigned long);
59291716Sken
60291716Sken	mtx_lock_spin(&t->mtx);
61291716Sken	if (callout_pending(&t->callout)) {
62291716Sken		/* callout was reset */
63291716Sken		mtx_unlock_spin(&t->mtx);
64291716Sken		return;
65291716Sken	}
66291716Sken	if (!callout_active(&t->callout)) {
67291716Sken		/* callout was stopped */
68291716Sken		mtx_unlock_spin(&t->mtx);
69291716Sken		return;
70291716Sken	}
71291716Sken	callout_deactivate(&t->callout);
72291716Sken
73291716Sken	function = t->function;
74291716Sken	mtx_unlock_spin(&t->mtx);
75291716Sken
76291716Sken	function(t->data);
77291716Sken}
78291716Sken
79291716Skenvoid
80291716Skeninit_timer(struct timer_list *t)
81291716Sken{
82291716Sken	mtx_init(&t->mtx, "dahdi timer lock", NULL, MTX_SPIN);
83291716Sken	callout_init(&t->callout, 1);
84291716Sken	t->expires = 0;
85291716Sken	/*
86291716Sken	 * function and data are not initialized intentionally:
87291716Sken	 * they are not initialized by Linux implementation too
88291716Sken	 */
89291716Sken}
90291716Sken
91291716Skenvoid
92291716Skensetup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data)
93291716Sken{
94291716Sken	t->function = function;
95291716Sken	t->data = data;
96291716Sken	init_timer(t);
97291716Sken}
98291716Sken
99291716Skenvoid
100291716Skenmod_timer(struct timer_list *t, unsigned long expires)
101291716Sken{
102291716Sken	mtx_lock_spin(&t->mtx);
103291716Sken	callout_reset(&t->callout, expires - jiffies, run_timer, t);
104291716Sken	mtx_unlock_spin(&t->mtx);
105291716Sken}
106291716Sken
107291716Skenvoid
108291716Skenadd_timer(struct timer_list *t)
109291716Sken{
110291716Sken	mod_timer(t, t->expires);
111291716Sken}
112291716Sken
113291716Skenint
114291716Skendel_timer_sync(struct timer_list *t)
115291716Sken{
116291716Sken	mtx_lock_spin(&t->mtx);
117291716Sken	callout_stop(&t->callout);
118291716Sken	mtx_unlock_spin(&t->mtx);
119291716Sken
120291716Sken	mtx_destroy(&t->mtx);
121291716Sken	return 0;
122291716Sken}
123291716Sken
124291716Skenint
125291716Skendel_timer(struct timer_list *t)
126291716Sken{
127291716Sken	del_timer_sync(t);
128291716Sken	return 0;
129291716Sken}
130291716Sken
131291716Sken/*
132291716Sken * Completion API
133291716Sken */
134291716Skenvoid
135291716Skeninit_completion(struct completion *c)
136291716Sken{
137291716Sken	cv_init(&c->cv, "VCHI completion cv");
138291716Sken	mtx_init(&c->lock, "VCHI completion lock", "condvar", MTX_DEF);
139291716Sken	c->done = 0;
140291716Sken}
141291716Sken
142291716Skenvoid
143291716Skendestroy_completion(struct completion *c)
144291716Sken{
145291716Sken	cv_destroy(&c->cv);
146291716Sken	mtx_destroy(&c->lock);
147291716Sken}
148291716Sken
149291716Skenvoid
150291716Skencomplete(struct completion *c)
151291716Sken{
152291716Sken	mtx_lock(&c->lock);
153291716Sken
154291716Sken	if (c->done >= 0) {
155291716Sken		KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */
156291716Sken		c->done++;
157291716Sken		cv_signal(&c->cv);
158291716Sken	} else {
159291716Sken		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
160291716Sken	}
161291716Sken
162291716Sken	mtx_unlock(&c->lock);
163291716Sken}
164291716Sken
165291716Skenvoid
166291716Skencomplete_all(struct completion *c)
167291716Sken{
168291716Sken	mtx_lock(&c->lock);
169291716Sken
170291716Sken	if (c->done >= 0) {
171291716Sken		KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */
172291716Sken		c->done = -1;
173291716Sken		cv_broadcast(&c->cv);
174291716Sken	} else {
175291716Sken		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
176291716Sken	}
177291716Sken
178291716Sken	mtx_unlock(&c->lock);
179291716Sken}
180291716Sken
181291716Skenvoid
182291716SkenINIT_COMPLETION_locked(struct completion *c)
183291716Sken{
184291716Sken	mtx_lock(&c->lock);
185291716Sken
186291716Sken	c->done = 0;
187291716Sken
188291716Sken	mtx_unlock(&c->lock);
189291716Sken}
190291716Sken
191291716Skenstatic void
192291716Sken_completion_claim(struct completion *c)
193291716Sken{
194291716Sken
195291716Sken	KASSERT(mtx_owned(&c->lock),
196291716Sken	    ("_completion_claim should be called with acquired lock"));
197291716Sken	KASSERT(c->done != 0, ("_completion_claim on non-waited completion"));
198291716Sken	if (c->done > 0)
199291716Sken		c->done--;
200291716Sken	else
201291716Sken		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
202291716Sken}
203291716Sken
204291716Skenvoid
205291716Skenwait_for_completion(struct completion *c)
206291716Sken{
207291716Sken	mtx_lock(&c->lock);
208291716Sken	if (!c->done)
209291716Sken		cv_wait(&c->cv, &c->lock);
210291716Sken	c->done--;
211291716Sken	mtx_unlock(&c->lock);
212291716Sken}
213291716Sken
214291716Skenint
215291716Skentry_wait_for_completion(struct completion *c)
216291716Sken{
217291716Sken	int res = 0;
218291716Sken
219291716Sken	mtx_lock(&c->lock);
220291716Sken	if (!c->done)
221291716Sken		res = 1;
222291716Sken	else
223291716Sken		c->done--;
224291716Sken	mtx_unlock(&c->lock);
225291716Sken	return res == 0;
226291716Sken}
227291716Sken
228291716Skenint
229291716Skenwait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout)
230291716Sken{
231291716Sken	int res = 0;
232291716Sken	unsigned long start, now;
233291716Sken	start = jiffies;
234291716Sken
235291716Sken	mtx_lock(&c->lock);
236291716Sken	while (c->done == 0) {
237291716Sken		res = cv_timedwait_sig(&c->cv, &c->lock, timeout);
238291716Sken		if (res)
239291716Sken			goto out;
240291716Sken		now = jiffies;
241291716Sken		if (timeout < (now - start)) {
242291716Sken			res = EWOULDBLOCK;
243291716Sken			goto out;
244291716Sken		}
245291716Sken
246291716Sken		timeout -= (now - start);
247291716Sken		start = now;
248291716Sken	}
249291716Sken
250291716Sken	_completion_claim(c);
251291716Sken	res = 0;
252291716Sken
253291716Skenout:
254291716Sken	mtx_unlock(&c->lock);
255291716Sken
256291716Sken	if (res == EWOULDBLOCK) {
257291716Sken		return 0;
258291716Sken	} else if ((res == EINTR) || (res == ERESTART)) {
259291716Sken		return -ERESTART;
260291716Sken	} else {
261291716Sken		KASSERT((res == 0), ("res = %d", res));
262291716Sken		return timeout;
263291716Sken	}
264291716Sken}
265291716Sken
266291716Skenint
267291716Skenwait_for_completion_interruptible(struct completion *c)
268291716Sken{
269291716Sken	int res = 0;
270291716Sken
271291716Sken	mtx_lock(&c->lock);
272291716Sken	while (c->done == 0) {
273291716Sken		res = cv_wait_sig(&c->cv, &c->lock);
274291716Sken		if (res)
275291716Sken			goto out;
276291716Sken	}
277291716Sken
278291716Sken	_completion_claim(c);
279291716Sken
280291716Skenout:
281291716Sken	mtx_unlock(&c->lock);
282291716Sken
283291716Sken	if ((res == EINTR) || (res == ERESTART))
284		res = -ERESTART;
285	return res;
286}
287
288int
289wait_for_completion_killable(struct completion *c)
290{
291
292	return wait_for_completion_interruptible(c);
293}
294
295/*
296 * Semaphore API
297 */
298
299void sema_sysinit(void *arg)
300{
301	struct semaphore *s = arg;
302
303	printf("sema_sysinit\n");
304	_sema_init(s, 1);
305}
306
307void
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
317void
318_sema_destroy(struct semaphore *s)
319{
320	mtx_destroy(&s->mtx);
321	cv_destroy(&s->cv);
322}
323
324void
325down(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
339int
340down_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
368int
369down_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
390void
391up(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 */
404void
405rlprintf(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
418void
419device_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
437void
438flush_signals(VCHIQ_THREAD_T thr)
439{
440	printf("Implement ME: %s\n", __func__);
441}
442
443int
444fatal_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
458static int thread_data_slot = 0;
459
460struct thread_data {
461	void *data;
462	int (*threadfn)(void *);
463};
464
465static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
466
467static void
468kthread_wrapper(void *data)
469{
470	struct thread_data *slot;
471
472	slot = data;
473	slot->threadfn(slot->data);
474}
475
476VCHIQ_THREAD_T
477vchiq_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
511void
512set_user_nice(VCHIQ_THREAD_T thr, int nice)
513{
514	/* NOOP */
515}
516
517void
518wake_up_process(VCHIQ_THREAD_T thr)
519{
520	/* NOOP */
521}
522
523void
524bcm_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