1d0c4f7d9Sjmcneill /*-
2d0c4f7d9Sjmcneill * Copyright (c) 2010 Max Khon <fjoe@freebsd.org>
3d0c4f7d9Sjmcneill * All rights reserved.
4d0c4f7d9Sjmcneill *
5d0c4f7d9Sjmcneill * This software was developed by Max Khon under sponsorship from
6d0c4f7d9Sjmcneill * the FreeBSD Foundation and Ethon Technologies GmbH.
7d0c4f7d9Sjmcneill *
8d0c4f7d9Sjmcneill * Redistribution and use in source and binary forms, with or without
9d0c4f7d9Sjmcneill * modification, are permitted provided that the following conditions
10d0c4f7d9Sjmcneill * are met:
11d0c4f7d9Sjmcneill * 1. Redistributions of source code must retain the above copyright
12d0c4f7d9Sjmcneill * notice, this list of conditions and the following disclaimer.
13d0c4f7d9Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
14d0c4f7d9Sjmcneill * notice, this list of conditions and the following disclaimer in the
15d0c4f7d9Sjmcneill * documentation and/or other materials provided with the distribution.
16d0c4f7d9Sjmcneill *
17d0c4f7d9Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d0c4f7d9Sjmcneill * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d0c4f7d9Sjmcneill * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d0c4f7d9Sjmcneill * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d0c4f7d9Sjmcneill * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d0c4f7d9Sjmcneill * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d0c4f7d9Sjmcneill * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d0c4f7d9Sjmcneill * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d0c4f7d9Sjmcneill * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d0c4f7d9Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d0c4f7d9Sjmcneill * SUCH DAMAGE.
28d0c4f7d9Sjmcneill *
29*5fcdcb15Sskrll * $Id: vchi_bsd.c,v 1.10 2017/11/05 09:11:43 skrll Exp $
30d0c4f7d9Sjmcneill */
31d0c4f7d9Sjmcneill
32d0c4f7d9Sjmcneill #include <sys/types.h>
33d0c4f7d9Sjmcneill #include <sys/bus.h>
34d0c4f7d9Sjmcneill #include <sys/callout.h>
35d0c4f7d9Sjmcneill #include <sys/param.h>
36d0c4f7d9Sjmcneill #include <sys/proc.h>
37d0c4f7d9Sjmcneill #include <sys/systm.h>
38d0c4f7d9Sjmcneill
39d0c4f7d9Sjmcneill #include <interface/compat/vchi_bsd.h>
40d0c4f7d9Sjmcneill
41d0c4f7d9Sjmcneill MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");
42d0c4f7d9Sjmcneill
43d0c4f7d9Sjmcneill /*
44d0c4f7d9Sjmcneill * Timer API
45d0c4f7d9Sjmcneill */
46d0c4f7d9Sjmcneill static void
run_timer(void * arg)47d0c4f7d9Sjmcneill run_timer(void *arg)
48d0c4f7d9Sjmcneill {
49d0c4f7d9Sjmcneill struct timer_list *t = (struct timer_list *) arg;
50d0c4f7d9Sjmcneill void (*function)(unsigned long);
51d0c4f7d9Sjmcneill
52d0c4f7d9Sjmcneill spin_lock(&t->mtx);
53d0c4f7d9Sjmcneill if (callout_pending(&t->callout)) {
54d0c4f7d9Sjmcneill /* callout was reset */
55d0c4f7d9Sjmcneill spin_unlock(&t->mtx);
56d0c4f7d9Sjmcneill return;
57d0c4f7d9Sjmcneill }
58d0c4f7d9Sjmcneill if (!callout_active(&t->callout)) {
59d0c4f7d9Sjmcneill /* callout was stopped */
60d0c4f7d9Sjmcneill spin_unlock(&t->mtx);
61d0c4f7d9Sjmcneill return;
62d0c4f7d9Sjmcneill }
63d0c4f7d9Sjmcneill callout_ack(&t->callout);
64d0c4f7d9Sjmcneill
65d0c4f7d9Sjmcneill function = t->function;
66d0c4f7d9Sjmcneill spin_unlock(&t->mtx);
67d0c4f7d9Sjmcneill
68d0c4f7d9Sjmcneill function(t->data);
69d0c4f7d9Sjmcneill }
70d0c4f7d9Sjmcneill
71d0c4f7d9Sjmcneill void
init_timer(struct timer_list * t)72d0c4f7d9Sjmcneill init_timer(struct timer_list *t)
73d0c4f7d9Sjmcneill {
74d0c4f7d9Sjmcneill spin_lock_init(&t->mtx);
75d0c4f7d9Sjmcneill callout_init(&t->callout, CALLOUT_MPSAFE);
76d0c4f7d9Sjmcneill t->expires = 0;
77d0c4f7d9Sjmcneill /*
78d0c4f7d9Sjmcneill * function and data are not initialized intentionally:
79d0c4f7d9Sjmcneill * they are not initialized by Linux implementation too
80d0c4f7d9Sjmcneill */
81d0c4f7d9Sjmcneill }
82d0c4f7d9Sjmcneill
83d0c4f7d9Sjmcneill void
setup_timer(struct timer_list * t,void (* function)(unsigned long),unsigned long data)84d0c4f7d9Sjmcneill setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data)
85d0c4f7d9Sjmcneill {
86d0c4f7d9Sjmcneill t->function = function;
87d0c4f7d9Sjmcneill t->data = data;
88d0c4f7d9Sjmcneill init_timer(t);
89d0c4f7d9Sjmcneill }
90d0c4f7d9Sjmcneill
91d0c4f7d9Sjmcneill void
mod_timer(struct timer_list * t,unsigned long expires)92d0c4f7d9Sjmcneill mod_timer(struct timer_list *t, unsigned long expires)
93d0c4f7d9Sjmcneill {
94d0c4f7d9Sjmcneill spin_lock(&t->mtx);
95d0c4f7d9Sjmcneill callout_reset(&t->callout, expires - jiffies, run_timer, t);
96d0c4f7d9Sjmcneill spin_unlock(&t->mtx);
97d0c4f7d9Sjmcneill }
98d0c4f7d9Sjmcneill
99d0c4f7d9Sjmcneill void
add_timer(struct timer_list * t)100d0c4f7d9Sjmcneill add_timer(struct timer_list *t)
101d0c4f7d9Sjmcneill {
102d0c4f7d9Sjmcneill mod_timer(t, t->expires);
103d0c4f7d9Sjmcneill }
104d0c4f7d9Sjmcneill
105d0c4f7d9Sjmcneill int
del_timer_sync(struct timer_list * t)106d0c4f7d9Sjmcneill del_timer_sync(struct timer_list *t)
107d0c4f7d9Sjmcneill {
108d0c4f7d9Sjmcneill spin_lock(&t->mtx);
10995c59df5Sjmcneill callout_halt(&t->callout, &t->mtx);
110d0c4f7d9Sjmcneill spin_unlock(&t->mtx);
111d0c4f7d9Sjmcneill
112d0c4f7d9Sjmcneill spin_lock_destroy(&t->mtx);
113d0c4f7d9Sjmcneill return 0;
114d0c4f7d9Sjmcneill }
115d0c4f7d9Sjmcneill
116d0c4f7d9Sjmcneill int
del_timer(struct timer_list * t)117d0c4f7d9Sjmcneill del_timer(struct timer_list *t)
118d0c4f7d9Sjmcneill {
119d0c4f7d9Sjmcneill del_timer_sync(t);
120d0c4f7d9Sjmcneill return 0;
121d0c4f7d9Sjmcneill }
122d0c4f7d9Sjmcneill
123d0c4f7d9Sjmcneill /*
124d0c4f7d9Sjmcneill * Semaphore API
125d0c4f7d9Sjmcneill */
126d0c4f7d9Sjmcneill
sema_sysinit(void * arg)127d0c4f7d9Sjmcneill void sema_sysinit(void *arg)
128d0c4f7d9Sjmcneill {
129d0c4f7d9Sjmcneill struct semaphore *s = arg;
130d0c4f7d9Sjmcneill
131d0c4f7d9Sjmcneill printf("sema_sysinit\n");
132d0c4f7d9Sjmcneill _sema_init(s, 1);
133d0c4f7d9Sjmcneill }
134d0c4f7d9Sjmcneill
135d0c4f7d9Sjmcneill void
_sema_init(struct semaphore * s,int value)136d0c4f7d9Sjmcneill _sema_init(struct semaphore *s, int value)
137d0c4f7d9Sjmcneill {
138fe334a74Sskrll memset(s, 0, sizeof(*s));
139*5fcdcb15Sskrll mutex_init(&s->mtx, MUTEX_DEFAULT, IPL_VM);
140d0c4f7d9Sjmcneill cv_init(&s->cv, "semacv");
141d0c4f7d9Sjmcneill s->value = value;
142d0c4f7d9Sjmcneill }
143d0c4f7d9Sjmcneill
144d0c4f7d9Sjmcneill void
_sema_destroy(struct semaphore * s)145d0c4f7d9Sjmcneill _sema_destroy(struct semaphore *s)
146d0c4f7d9Sjmcneill {
147d0c4f7d9Sjmcneill mutex_destroy(&s->mtx);
148d0c4f7d9Sjmcneill cv_destroy(&s->cv);
149d0c4f7d9Sjmcneill }
150d0c4f7d9Sjmcneill
151d0c4f7d9Sjmcneill void
down(struct semaphore * s)152d0c4f7d9Sjmcneill down(struct semaphore *s)
153d0c4f7d9Sjmcneill {
154d0c4f7d9Sjmcneill
155d0c4f7d9Sjmcneill mutex_enter(&s->mtx);
156d0c4f7d9Sjmcneill while (s->value == 0) {
157d0c4f7d9Sjmcneill s->waiters++;
158d0c4f7d9Sjmcneill cv_wait(&s->cv, &s->mtx);
159d0c4f7d9Sjmcneill s->waiters--;
160d0c4f7d9Sjmcneill }
161d0c4f7d9Sjmcneill
162d0c4f7d9Sjmcneill s->value--;
163d0c4f7d9Sjmcneill mutex_exit(&s->mtx);
164d0c4f7d9Sjmcneill }
165d0c4f7d9Sjmcneill
166d0c4f7d9Sjmcneill int
down_interruptible(struct semaphore * s)167d0c4f7d9Sjmcneill down_interruptible(struct semaphore *s)
168d0c4f7d9Sjmcneill {
169d0c4f7d9Sjmcneill
170d0c4f7d9Sjmcneill mutex_enter(&s->mtx);
171d0c4f7d9Sjmcneill
172d0c4f7d9Sjmcneill while (s->value == 0) {
173d0c4f7d9Sjmcneill s->waiters++;
174d0eeb335Sskrll int ret = cv_wait_sig(&s->cv, &s->mtx);
175d0c4f7d9Sjmcneill s->waiters--;
176d0c4f7d9Sjmcneill
177d0c4f7d9Sjmcneill if (ret == EINTR || ret == ERESTART) {
178d0c4f7d9Sjmcneill mutex_exit(&s->mtx);
179f714ddc6Sskrll return -EINTR;
180d0c4f7d9Sjmcneill }
181d0c4f7d9Sjmcneill }
182d0c4f7d9Sjmcneill
183d0c4f7d9Sjmcneill s->value--;
184d0c4f7d9Sjmcneill mutex_exit(&s->mtx);
185d0c4f7d9Sjmcneill
186f714ddc6Sskrll return 0;
187d0c4f7d9Sjmcneill }
188d0c4f7d9Sjmcneill
189d0c4f7d9Sjmcneill int
down_trylock(struct semaphore * s)190d0c4f7d9Sjmcneill down_trylock(struct semaphore *s)
191d0c4f7d9Sjmcneill {
192d0eeb335Sskrll int ret = 1;
193d0c4f7d9Sjmcneill
194d0c4f7d9Sjmcneill mutex_enter(&s->mtx);
195d0c4f7d9Sjmcneill
196d0c4f7d9Sjmcneill if (s->value > 0) {
197d0c4f7d9Sjmcneill /* Success. */
198d0c4f7d9Sjmcneill s->value--;
199d0c4f7d9Sjmcneill ret = 0;
200d0c4f7d9Sjmcneill }
201d0c4f7d9Sjmcneill
202d0c4f7d9Sjmcneill mutex_exit(&s->mtx);
203d0c4f7d9Sjmcneill
204f714ddc6Sskrll return ret;
205d0c4f7d9Sjmcneill }
206d0c4f7d9Sjmcneill
207d0c4f7d9Sjmcneill void
up(struct semaphore * s)208d0c4f7d9Sjmcneill up(struct semaphore *s)
209d0c4f7d9Sjmcneill {
210d0c4f7d9Sjmcneill mutex_enter(&s->mtx);
211d0c4f7d9Sjmcneill s->value++;
212d0eeb335Sskrll if (s->value > 0 && s->waiters)
213d0c4f7d9Sjmcneill cv_signal(&s->cv);
214d0c4f7d9Sjmcneill
215d0c4f7d9Sjmcneill mutex_exit(&s->mtx);
216d0c4f7d9Sjmcneill }
217d0c4f7d9Sjmcneill
218d0c4f7d9Sjmcneill /*
219d0c4f7d9Sjmcneill * Logging API
220d0c4f7d9Sjmcneill */
221d0c4f7d9Sjmcneill void
rlprintf(int pps,const char * fmt,...)222d0c4f7d9Sjmcneill rlprintf(int pps, const char *fmt, ...)
223d0c4f7d9Sjmcneill {
224d0c4f7d9Sjmcneill va_list ap;
225d0c4f7d9Sjmcneill static struct timeval last_printf;
226d0c4f7d9Sjmcneill static int count;
227d0c4f7d9Sjmcneill
228d0c4f7d9Sjmcneill if (ppsratecheck(&last_printf, &count, pps)) {
229d0c4f7d9Sjmcneill va_start(ap, fmt);
230d0c4f7d9Sjmcneill vprintf(fmt, ap);
231d0c4f7d9Sjmcneill va_end(ap);
232d0c4f7d9Sjmcneill }
233d0c4f7d9Sjmcneill }
234d0c4f7d9Sjmcneill
235d0c4f7d9Sjmcneill void
device_rlprintf(int pps,device_t dev,const char * fmt,...)236d0c4f7d9Sjmcneill device_rlprintf(int pps, device_t dev, const char *fmt, ...)
237d0c4f7d9Sjmcneill {
238d0c4f7d9Sjmcneill va_list ap;
239d0c4f7d9Sjmcneill static struct timeval last_printf;
240d0c4f7d9Sjmcneill static int count;
241d0c4f7d9Sjmcneill
242d0c4f7d9Sjmcneill if (ppsratecheck(&last_printf, &count, pps)) {
243d0c4f7d9Sjmcneill va_start(ap, fmt);
244d0c4f7d9Sjmcneill device_print_prettyname(dev);
245d0c4f7d9Sjmcneill vprintf(fmt, ap);
246d0c4f7d9Sjmcneill va_end(ap);
247d0c4f7d9Sjmcneill }
248d0c4f7d9Sjmcneill }
249d0c4f7d9Sjmcneill
250d0c4f7d9Sjmcneill /*
251d0c4f7d9Sjmcneill * Signals API
252d0c4f7d9Sjmcneill */
253d0c4f7d9Sjmcneill
254d0c4f7d9Sjmcneill void
flush_signals(VCHIQ_THREAD_T thr)255d0c4f7d9Sjmcneill flush_signals(VCHIQ_THREAD_T thr)
256d0c4f7d9Sjmcneill {
257d0c4f7d9Sjmcneill printf("Implement ME: %s\n", __func__);
258d0c4f7d9Sjmcneill }
259d0c4f7d9Sjmcneill
260d0c4f7d9Sjmcneill int
fatal_signal_pending(VCHIQ_THREAD_T thr)261d0c4f7d9Sjmcneill fatal_signal_pending(VCHIQ_THREAD_T thr)
262d0c4f7d9Sjmcneill {
263d0c4f7d9Sjmcneill printf("Implement ME: %s\n", __func__);
264f714ddc6Sskrll return 0;
265d0c4f7d9Sjmcneill }
266d0c4f7d9Sjmcneill
267d0c4f7d9Sjmcneill /*
268d0c4f7d9Sjmcneill * kthread API
269d0c4f7d9Sjmcneill */
270d0c4f7d9Sjmcneill
271d0c4f7d9Sjmcneill /*
272d0c4f7d9Sjmcneill * This is a hack to avoid memory leak
273d0c4f7d9Sjmcneill */
274d0c4f7d9Sjmcneill #define MAX_THREAD_DATA_SLOTS 32
275d0c4f7d9Sjmcneill static int thread_data_slot = 0;
276d0c4f7d9Sjmcneill
277d0c4f7d9Sjmcneill struct thread_data {
278d0c4f7d9Sjmcneill void *data;
279d0c4f7d9Sjmcneill int (*threadfn)(void *);
280d0c4f7d9Sjmcneill };
281d0c4f7d9Sjmcneill
282d0c4f7d9Sjmcneill static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
283d0c4f7d9Sjmcneill
284d0c4f7d9Sjmcneill static void
kthread_wrapper(void * data)285d0c4f7d9Sjmcneill kthread_wrapper(void *data)
286d0c4f7d9Sjmcneill {
287d0c4f7d9Sjmcneill struct thread_data *slot;
288d0c4f7d9Sjmcneill
289d0c4f7d9Sjmcneill slot = data;
290d0c4f7d9Sjmcneill slot->threadfn(slot->data);
291d0c4f7d9Sjmcneill }
292d0c4f7d9Sjmcneill
293d0c4f7d9Sjmcneill VCHIQ_THREAD_T
vchiq_thread_create(int (* threadfn)(void * data),void * data,const char namefmt[],...)294d0c4f7d9Sjmcneill vchiq_thread_create(int (*threadfn)(void *data),
295d0c4f7d9Sjmcneill void *data,
296d0c4f7d9Sjmcneill const char namefmt[], ...)
297d0c4f7d9Sjmcneill {
298d0c4f7d9Sjmcneill VCHIQ_THREAD_T newt;
299d0c4f7d9Sjmcneill va_list ap;
300d0c4f7d9Sjmcneill char name[MAXCOMLEN+1];
301d0c4f7d9Sjmcneill struct thread_data *slot;
302d0c4f7d9Sjmcneill
303d0c4f7d9Sjmcneill if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) {
304d0c4f7d9Sjmcneill printf("kthread_create: out of thread data slots\n");
305f714ddc6Sskrll return NULL;
306d0c4f7d9Sjmcneill }
307d0c4f7d9Sjmcneill
308d0c4f7d9Sjmcneill slot = &thread_slots[thread_data_slot];
309d0c4f7d9Sjmcneill slot->data = data;
310d0c4f7d9Sjmcneill slot->threadfn = threadfn;
311d0c4f7d9Sjmcneill
312d0c4f7d9Sjmcneill va_start(ap, namefmt);
313d0c4f7d9Sjmcneill vsnprintf(name, sizeof(name), namefmt, ap);
314d0c4f7d9Sjmcneill va_end(ap);
315d0c4f7d9Sjmcneill
316d0c4f7d9Sjmcneill newt = NULL;
31795c59df5Sjmcneill if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, kthread_wrapper,
31895c59df5Sjmcneill slot, &newt, "%s", name) != 0) {
319d0c4f7d9Sjmcneill /* Just to be sure */
320d0c4f7d9Sjmcneill newt = NULL;
321d0c4f7d9Sjmcneill } else {
322d0c4f7d9Sjmcneill thread_data_slot++;
323d0c4f7d9Sjmcneill }
324d0c4f7d9Sjmcneill
325d0c4f7d9Sjmcneill return newt;
326d0c4f7d9Sjmcneill }
327d0c4f7d9Sjmcneill
328d0c4f7d9Sjmcneill void
set_user_nice(VCHIQ_THREAD_T thr,int nice)329d0c4f7d9Sjmcneill set_user_nice(VCHIQ_THREAD_T thr, int nice)
330d0c4f7d9Sjmcneill {
331d0c4f7d9Sjmcneill /* NOOP */
332d0c4f7d9Sjmcneill }
333d0c4f7d9Sjmcneill
334d0c4f7d9Sjmcneill void
wake_up_process(VCHIQ_THREAD_T thr)335d0c4f7d9Sjmcneill wake_up_process(VCHIQ_THREAD_T thr)
336d0c4f7d9Sjmcneill {
337d0c4f7d9Sjmcneill /* NOOP */
338d0c4f7d9Sjmcneill }
339