vchi_bsd.c revision 283291
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
49MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");
50
51/*
52 * Timer API
53 */
54static void
55run_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
79void
80init_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
91void
92setup_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
99void
100mod_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
107void
108add_timer(struct timer_list *t)
109{
110	mod_timer(t, t->expires);
111}
112
113int
114del_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
124int
125del_timer(struct timer_list *t)
126{
127	del_timer_sync(t);
128	return 0;
129}
130
131/*
132 * Completion API
133 */
134void
135init_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
142void
143destroy_completion(struct completion *c)
144{
145	cv_destroy(&c->cv);
146	mtx_destroy(&c->lock);
147}
148
149void
150complete(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
165void
166complete_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
181void
182INIT_COMPLETION_locked(struct completion *c)
183{
184	mtx_lock(&c->lock);
185
186	c->done = 0;
187
188	mtx_unlock(&c->lock);
189}
190
191static 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
204void
205wait_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
214int
215try_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
228int
229wait_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
253out:
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
266int
267wait_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
280out:
281	mtx_unlock(&c->lock);
282
283	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