1278277Sgonzo/*-
2278277Sgonzo * Copyright (c) 2010 Max Khon <fjoe@freebsd.org>
3278277Sgonzo * All rights reserved.
4278277Sgonzo *
5278277Sgonzo * This software was developed by Max Khon under sponsorship from
6278277Sgonzo * the FreeBSD Foundation and Ethon Technologies GmbH.
7278277Sgonzo *
8278277Sgonzo * Redistribution and use in source and binary forms, with or without
9278277Sgonzo * modification, are permitted provided that the following conditions
10278277Sgonzo * are met:
11278277Sgonzo * 1. Redistributions of source code must retain the above copyright
12278277Sgonzo *    notice, this list of conditions and the following disclaimer.
13278277Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
14278277Sgonzo *    notice, this list of conditions and the following disclaimer in the
15278277Sgonzo *    documentation and/or other materials provided with the distribution.
16278277Sgonzo *
17278277Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18278277Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19278277Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20278277Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21278277Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22278277Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23278277Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24278277Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25278277Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26278277Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27278277Sgonzo * SUCH DAMAGE.
28278277Sgonzo *
29278277Sgonzo * $Id: bsd-compat.c 9253 2010-09-02 10:12:09Z fjoe $
30278277Sgonzo */
31278277Sgonzo
32278277Sgonzo#include <sys/types.h>
33278277Sgonzo#include <sys/limits.h>
34278277Sgonzo#include <sys/bus.h>
35278277Sgonzo#include <sys/callout.h>
36278277Sgonzo#include <sys/firmware.h>
37278277Sgonzo#include <sys/param.h>
38278277Sgonzo#include <sys/proc.h>
39278277Sgonzo#include <sys/syscallsubr.h>
40278277Sgonzo#include <sys/systm.h>
41278277Sgonzo#include <sys/taskqueue.h>
42278277Sgonzo
43278277Sgonzo#include <machine/stdarg.h>
44278277Sgonzo
45278277Sgonzo#include "mbox_if.h"
46278277Sgonzo
47278277Sgonzo#include <interface/compat/vchi_bsd.h>
48278277Sgonzo
49278277SgonzoMALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");
50278277Sgonzo
51278277Sgonzo/*
52278277Sgonzo * Timer API
53278277Sgonzo */
54278277Sgonzostatic void
55278277Sgonzorun_timer(void *arg)
56278277Sgonzo{
57278277Sgonzo	struct timer_list *t = (struct timer_list *) arg;
58278277Sgonzo	void (*function)(unsigned long);
59278277Sgonzo
60278277Sgonzo	mtx_lock_spin(&t->mtx);
61278277Sgonzo	if (callout_pending(&t->callout)) {
62278277Sgonzo		/* callout was reset */
63278277Sgonzo		mtx_unlock_spin(&t->mtx);
64278277Sgonzo		return;
65278277Sgonzo	}
66278277Sgonzo	if (!callout_active(&t->callout)) {
67278277Sgonzo		/* callout was stopped */
68278277Sgonzo		mtx_unlock_spin(&t->mtx);
69278277Sgonzo		return;
70278277Sgonzo	}
71278277Sgonzo	callout_deactivate(&t->callout);
72278277Sgonzo
73278277Sgonzo	function = t->function;
74278277Sgonzo	mtx_unlock_spin(&t->mtx);
75278277Sgonzo
76278277Sgonzo	function(t->data);
77278277Sgonzo}
78278277Sgonzo
79278277Sgonzovoid
80278277Sgonzoinit_timer(struct timer_list *t)
81278277Sgonzo{
82278277Sgonzo	mtx_init(&t->mtx, "dahdi timer lock", NULL, MTX_SPIN);
83283291Sjkim	callout_init(&t->callout, 1);
84278277Sgonzo	t->expires = 0;
85278277Sgonzo	/*
86278277Sgonzo	 * function and data are not initialized intentionally:
87278277Sgonzo	 * they are not initialized by Linux implementation too
88278277Sgonzo	 */
89278277Sgonzo}
90278277Sgonzo
91278277Sgonzovoid
92278277Sgonzosetup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data)
93278277Sgonzo{
94278277Sgonzo	t->function = function;
95278277Sgonzo	t->data = data;
96278277Sgonzo	init_timer(t);
97278277Sgonzo}
98278277Sgonzo
99278277Sgonzovoid
100278277Sgonzomod_timer(struct timer_list *t, unsigned long expires)
101278277Sgonzo{
102278277Sgonzo	mtx_lock_spin(&t->mtx);
103278277Sgonzo	callout_reset(&t->callout, expires - jiffies, run_timer, t);
104278277Sgonzo	mtx_unlock_spin(&t->mtx);
105278277Sgonzo}
106278277Sgonzo
107278277Sgonzovoid
108278277Sgonzoadd_timer(struct timer_list *t)
109278277Sgonzo{
110278277Sgonzo	mod_timer(t, t->expires);
111278277Sgonzo}
112278277Sgonzo
113278277Sgonzoint
114278277Sgonzodel_timer_sync(struct timer_list *t)
115278277Sgonzo{
116278277Sgonzo	mtx_lock_spin(&t->mtx);
117278277Sgonzo	callout_stop(&t->callout);
118278277Sgonzo	mtx_unlock_spin(&t->mtx);
119278277Sgonzo
120278277Sgonzo	mtx_destroy(&t->mtx);
121278277Sgonzo	return 0;
122278277Sgonzo}
123278277Sgonzo
124278277Sgonzoint
125278277Sgonzodel_timer(struct timer_list *t)
126278277Sgonzo{
127278277Sgonzo	del_timer_sync(t);
128278277Sgonzo	return 0;
129278277Sgonzo}
130278277Sgonzo
131278277Sgonzo/*
132278277Sgonzo * Completion API
133278277Sgonzo */
134278277Sgonzovoid
135278277Sgonzoinit_completion(struct completion *c)
136278277Sgonzo{
137278277Sgonzo	cv_init(&c->cv, "VCHI completion cv");
138278277Sgonzo	mtx_init(&c->lock, "VCHI completion lock", "condvar", MTX_DEF);
139278277Sgonzo	c->done = 0;
140278277Sgonzo}
141278277Sgonzo
142278277Sgonzovoid
143278277Sgonzodestroy_completion(struct completion *c)
144278277Sgonzo{
145278277Sgonzo	cv_destroy(&c->cv);
146278277Sgonzo	mtx_destroy(&c->lock);
147278277Sgonzo}
148278277Sgonzo
149278277Sgonzovoid
150278277Sgonzocomplete(struct completion *c)
151278277Sgonzo{
152278277Sgonzo	mtx_lock(&c->lock);
153278277Sgonzo
154278277Sgonzo	if (c->done >= 0) {
155278277Sgonzo		KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */
156278277Sgonzo		c->done++;
157278277Sgonzo		cv_signal(&c->cv);
158278277Sgonzo	} else {
159278277Sgonzo		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
160278277Sgonzo	}
161278277Sgonzo
162278277Sgonzo	mtx_unlock(&c->lock);
163278277Sgonzo}
164278277Sgonzo
165278277Sgonzovoid
166278277Sgonzocomplete_all(struct completion *c)
167278277Sgonzo{
168278277Sgonzo	mtx_lock(&c->lock);
169278277Sgonzo
170278277Sgonzo	if (c->done >= 0) {
171278277Sgonzo		KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */
172278277Sgonzo		c->done = -1;
173278277Sgonzo		cv_broadcast(&c->cv);
174278277Sgonzo	} else {
175278277Sgonzo		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
176278277Sgonzo	}
177278277Sgonzo
178278277Sgonzo	mtx_unlock(&c->lock);
179278277Sgonzo}
180278277Sgonzo
181278277Sgonzovoid
182278277SgonzoINIT_COMPLETION_locked(struct completion *c)
183278277Sgonzo{
184278277Sgonzo	mtx_lock(&c->lock);
185278277Sgonzo
186278277Sgonzo	c->done = 0;
187278277Sgonzo
188278277Sgonzo	mtx_unlock(&c->lock);
189278277Sgonzo}
190278277Sgonzo
191278277Sgonzostatic void
192278277Sgonzo_completion_claim(struct completion *c)
193278277Sgonzo{
194278277Sgonzo
195278277Sgonzo	KASSERT(mtx_owned(&c->lock),
196278277Sgonzo	    ("_completion_claim should be called with acquired lock"));
197278277Sgonzo	KASSERT(c->done != 0, ("_completion_claim on non-waited completion"));
198278277Sgonzo	if (c->done > 0)
199278277Sgonzo		c->done--;
200278277Sgonzo	else
201278277Sgonzo		KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
202278277Sgonzo}
203278277Sgonzo
204278277Sgonzovoid
205278277Sgonzowait_for_completion(struct completion *c)
206278277Sgonzo{
207278277Sgonzo	mtx_lock(&c->lock);
208278277Sgonzo	if (!c->done)
209278277Sgonzo		cv_wait(&c->cv, &c->lock);
210278277Sgonzo	c->done--;
211278277Sgonzo	mtx_unlock(&c->lock);
212278277Sgonzo}
213278277Sgonzo
214278277Sgonzoint
215278277Sgonzotry_wait_for_completion(struct completion *c)
216278277Sgonzo{
217278277Sgonzo	int res = 0;
218278277Sgonzo
219278277Sgonzo	mtx_lock(&c->lock);
220278277Sgonzo	if (!c->done)
221278277Sgonzo		res = 1;
222278277Sgonzo	else
223278277Sgonzo		c->done--;
224278277Sgonzo	mtx_unlock(&c->lock);
225278277Sgonzo	return res == 0;
226278277Sgonzo}
227278277Sgonzo
228278277Sgonzoint
229278277Sgonzowait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout)
230278277Sgonzo{
231278277Sgonzo	int res = 0;
232278277Sgonzo	unsigned long start, now;
233278277Sgonzo	start = jiffies;
234278277Sgonzo
235278277Sgonzo	mtx_lock(&c->lock);
236278277Sgonzo	while (c->done == 0) {
237278277Sgonzo		res = cv_timedwait_sig(&c->cv, &c->lock, timeout);
238278277Sgonzo		if (res)
239278277Sgonzo			goto out;
240278277Sgonzo		now = jiffies;
241278277Sgonzo		if (timeout < (now - start)) {
242278277Sgonzo			res = EWOULDBLOCK;
243278277Sgonzo			goto out;
244278277Sgonzo		}
245278277Sgonzo
246278277Sgonzo		timeout -= (now - start);
247278277Sgonzo		start = now;
248278277Sgonzo	}
249278277Sgonzo
250278277Sgonzo	_completion_claim(c);
251278277Sgonzo	res = 0;
252278277Sgonzo
253278277Sgonzoout:
254278277Sgonzo	mtx_unlock(&c->lock);
255278277Sgonzo
256278277Sgonzo	if (res == EWOULDBLOCK) {
257278277Sgonzo		return 0;
258278277Sgonzo	} else if ((res == EINTR) || (res == ERESTART)) {
259278277Sgonzo		return -ERESTART;
260278277Sgonzo	} else {
261278277Sgonzo		KASSERT((res == 0), ("res = %d", res));
262278277Sgonzo		return timeout;
263278277Sgonzo	}
264278277Sgonzo}
265278277Sgonzo
266278277Sgonzoint
267278277Sgonzowait_for_completion_interruptible(struct completion *c)
268278277Sgonzo{
269278277Sgonzo	int res = 0;
270278277Sgonzo
271278277Sgonzo	mtx_lock(&c->lock);
272278277Sgonzo	while (c->done == 0) {
273278277Sgonzo		res = cv_wait_sig(&c->cv, &c->lock);
274278277Sgonzo		if (res)
275278277Sgonzo			goto out;
276278277Sgonzo	}
277278277Sgonzo
278278277Sgonzo	_completion_claim(c);
279278277Sgonzo
280278277Sgonzoout:
281278277Sgonzo	mtx_unlock(&c->lock);
282278277Sgonzo
283278277Sgonzo	if ((res == EINTR) || (res == ERESTART))
284278277Sgonzo		res = -ERESTART;
285278277Sgonzo	return res;
286278277Sgonzo}
287278277Sgonzo
288278277Sgonzoint
289278277Sgonzowait_for_completion_killable(struct completion *c)
290278277Sgonzo{
291278277Sgonzo
292278277Sgonzo	return wait_for_completion_interruptible(c);
293278277Sgonzo}
294278277Sgonzo
295278277Sgonzo/*
296278277Sgonzo * Semaphore API
297278277Sgonzo */
298278277Sgonzo
299278277Sgonzovoid sema_sysinit(void *arg)
300278277Sgonzo{
301278277Sgonzo	struct semaphore *s = arg;
302278277Sgonzo
303278277Sgonzo	_sema_init(s, 1);
304278277Sgonzo}
305278277Sgonzo
306278277Sgonzovoid
307278277Sgonzo_sema_init(struct semaphore *s, int value)
308278277Sgonzo{
309278277Sgonzo	bzero(s, sizeof(*s));
310278277Sgonzo	mtx_init(&s->mtx, "sema lock", "VCHIQ sepmaphore backing lock",
311278277Sgonzo		MTX_DEF | MTX_NOWITNESS | MTX_QUIET);
312278277Sgonzo	cv_init(&s->cv, "sema cv");
313278277Sgonzo	s->value = value;
314278277Sgonzo}
315278277Sgonzo
316278277Sgonzovoid
317278277Sgonzo_sema_destroy(struct semaphore *s)
318278277Sgonzo{
319278277Sgonzo	mtx_destroy(&s->mtx);
320278277Sgonzo	cv_destroy(&s->cv);
321278277Sgonzo}
322278277Sgonzo
323278277Sgonzovoid
324278277Sgonzodown(struct semaphore *s)
325278277Sgonzo{
326278277Sgonzo
327278277Sgonzo	mtx_lock(&s->mtx);
328278277Sgonzo	while (s->value == 0) {
329278277Sgonzo		s->waiters++;
330278277Sgonzo		cv_wait(&s->cv, &s->mtx);
331278277Sgonzo		s->waiters--;
332278277Sgonzo	}
333278277Sgonzo
334278277Sgonzo	s->value--;
335278277Sgonzo	mtx_unlock(&s->mtx);
336278277Sgonzo}
337278277Sgonzo
338278277Sgonzoint
339278277Sgonzodown_interruptible(struct semaphore *s)
340278277Sgonzo{
341278277Sgonzo	int ret ;
342278277Sgonzo
343278277Sgonzo	ret = 0;
344278277Sgonzo
345278277Sgonzo	mtx_lock(&s->mtx);
346278277Sgonzo
347278277Sgonzo	while (s->value == 0) {
348278277Sgonzo		s->waiters++;
349278277Sgonzo		ret = cv_wait_sig(&s->cv, &s->mtx);
350278277Sgonzo		s->waiters--;
351278277Sgonzo
352278277Sgonzo		if (ret == EINTR) {
353278277Sgonzo			mtx_unlock(&s->mtx);
354278277Sgonzo			return (-EINTR);
355278277Sgonzo		}
356278277Sgonzo
357278277Sgonzo		if (ret == ERESTART)
358278277Sgonzo			continue;
359278277Sgonzo	}
360278277Sgonzo
361278277Sgonzo	s->value--;
362278277Sgonzo	mtx_unlock(&s->mtx);
363278277Sgonzo
364278277Sgonzo	return (0);
365278277Sgonzo}
366278277Sgonzo
367278277Sgonzoint
368278277Sgonzodown_trylock(struct semaphore *s)
369278277Sgonzo{
370278277Sgonzo	int ret;
371278277Sgonzo
372278277Sgonzo	ret = 0;
373278277Sgonzo
374278277Sgonzo	mtx_lock(&s->mtx);
375278277Sgonzo
376278277Sgonzo	if (s->value > 0) {
377278277Sgonzo		/* Success. */
378278277Sgonzo		s->value--;
379278277Sgonzo		ret = 0;
380278277Sgonzo	} else {
381278277Sgonzo		ret = -EAGAIN;
382278277Sgonzo	}
383278277Sgonzo
384278277Sgonzo	mtx_unlock(&s->mtx);
385278277Sgonzo
386278277Sgonzo	return (ret);
387278277Sgonzo}
388278277Sgonzo
389278277Sgonzovoid
390278277Sgonzoup(struct semaphore *s)
391278277Sgonzo{
392278277Sgonzo	mtx_lock(&s->mtx);
393278277Sgonzo	s->value++;
394278277Sgonzo	if (s->waiters && s->value > 0)
395278277Sgonzo		cv_signal(&s->cv);
396278277Sgonzo
397278277Sgonzo	mtx_unlock(&s->mtx);
398278277Sgonzo}
399278277Sgonzo
400278277Sgonzo/*
401278277Sgonzo * Logging API
402278277Sgonzo */
403278277Sgonzovoid
404278277Sgonzorlprintf(int pps, const char *fmt, ...)
405278277Sgonzo{
406278277Sgonzo	va_list ap;
407278277Sgonzo	static struct timeval last_printf;
408278277Sgonzo	static int count;
409278277Sgonzo
410278277Sgonzo	if (ppsratecheck(&last_printf, &count, pps)) {
411278277Sgonzo		va_start(ap, fmt);
412278277Sgonzo		vprintf(fmt, ap);
413278277Sgonzo		va_end(ap);
414278277Sgonzo	}
415278277Sgonzo}
416278277Sgonzo
417278277Sgonzovoid
418278277Sgonzodevice_rlprintf(int pps, device_t dev, const char *fmt, ...)
419278277Sgonzo{
420278277Sgonzo	va_list ap;
421278277Sgonzo	static struct timeval last_printf;
422278277Sgonzo	static int count;
423278277Sgonzo
424278277Sgonzo	if (ppsratecheck(&last_printf, &count, pps)) {
425278277Sgonzo		va_start(ap, fmt);
426278277Sgonzo		device_print_prettyname(dev);
427278277Sgonzo		vprintf(fmt, ap);
428278277Sgonzo		va_end(ap);
429278277Sgonzo	}
430278277Sgonzo}
431278277Sgonzo
432278277Sgonzo/*
433278277Sgonzo * Signals API
434278277Sgonzo */
435278277Sgonzo
436278277Sgonzovoid
437278277Sgonzoflush_signals(VCHIQ_THREAD_T thr)
438278277Sgonzo{
439278277Sgonzo	printf("Implement ME: %s\n", __func__);
440278277Sgonzo}
441278277Sgonzo
442278277Sgonzoint
443278277Sgonzofatal_signal_pending(VCHIQ_THREAD_T thr)
444278277Sgonzo{
445278277Sgonzo	printf("Implement ME: %s\n", __func__);
446278277Sgonzo	return (0);
447278277Sgonzo}
448278277Sgonzo
449278277Sgonzo/*
450278277Sgonzo * kthread API
451278277Sgonzo */
452278277Sgonzo
453278277Sgonzo/*
454278277Sgonzo *  This is a hack to avoid memory leak
455278277Sgonzo */
456278277Sgonzo#define MAX_THREAD_DATA_SLOTS	32
457278277Sgonzostatic int thread_data_slot = 0;
458278277Sgonzo
459278277Sgonzostruct thread_data {
460278277Sgonzo	void *data;
461278277Sgonzo	int (*threadfn)(void *);
462278277Sgonzo};
463278277Sgonzo
464278277Sgonzostatic struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
465278277Sgonzo
466278277Sgonzostatic void
467278277Sgonzokthread_wrapper(void *data)
468278277Sgonzo{
469278277Sgonzo	struct thread_data *slot;
470278277Sgonzo
471278277Sgonzo	slot = data;
472278277Sgonzo	slot->threadfn(slot->data);
473278277Sgonzo}
474278277Sgonzo
475278277SgonzoVCHIQ_THREAD_T
476278277Sgonzovchiq_thread_create(int (*threadfn)(void *data),
477278277Sgonzo	void *data,
478278277Sgonzo	const char namefmt[], ...)
479278277Sgonzo{
480278277Sgonzo	VCHIQ_THREAD_T newp;
481278277Sgonzo	va_list ap;
482278277Sgonzo	char name[MAXCOMLEN+1];
483278277Sgonzo	struct thread_data *slot;
484278277Sgonzo
485278277Sgonzo	if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) {
486278277Sgonzo		printf("kthread_create: out of thread data slots\n");
487278277Sgonzo		return (NULL);
488278277Sgonzo	}
489278277Sgonzo
490278277Sgonzo	slot = &thread_slots[thread_data_slot];
491278277Sgonzo	slot->data = data;
492278277Sgonzo	slot->threadfn = threadfn;
493278277Sgonzo
494278277Sgonzo	va_start(ap, namefmt);
495278277Sgonzo	vsnprintf(name, sizeof(name), namefmt, ap);
496278277Sgonzo	va_end(ap);
497278277Sgonzo
498278277Sgonzo	newp = NULL;
499278277Sgonzo	if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0,
500278277Sgonzo	    "%s", name) != 0) {
501278277Sgonzo		/* Just to be sure */
502278277Sgonzo		newp = NULL;
503278277Sgonzo	}
504278277Sgonzo	else
505278277Sgonzo		thread_data_slot++;
506278277Sgonzo
507278277Sgonzo	return newp;
508278277Sgonzo}
509278277Sgonzo
510278277Sgonzovoid
511278277Sgonzoset_user_nice(VCHIQ_THREAD_T thr, int nice)
512278277Sgonzo{
513278277Sgonzo	/* NOOP */
514278277Sgonzo}
515278277Sgonzo
516278277Sgonzovoid
517278277Sgonzowake_up_process(VCHIQ_THREAD_T thr)
518278277Sgonzo{
519278277Sgonzo	/* NOOP */
520278277Sgonzo}
521278277Sgonzo
522278277Sgonzovoid
523278277Sgonzobcm_mbox_write(int channel, uint32_t data)
524278277Sgonzo{
525278277Sgonzo	device_t mbox;
526278277Sgonzo
527278277Sgonzo        mbox = devclass_get_device(devclass_find("mbox"), 0);
528278277Sgonzo
529278277Sgonzo        if (mbox)
530278277Sgonzo                MBOX_WRITE(mbox, channel, data);
531278277Sgonzo}
532