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
run_timer(void * arg)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
vchiq_init_timer(struct timer_list * t)80 vchiq_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
vchiq_setup_timer(struct timer_list * t,void (* function)(unsigned long),unsigned long data)92 vchiq_setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data)
93 {
94 t->function = function;
95 t->data = data;
96 vchiq_init_timer(t);
97 }
98
99 void
vchiq_mod_timer(struct timer_list * t,unsigned long expires)100 vchiq_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
vchiq_add_timer(struct timer_list * t)108 vchiq_add_timer(struct timer_list *t)
109 {
110 vchiq_mod_timer(t, t->expires);
111 }
112
113 int
vchiq_del_timer_sync(struct timer_list * t)114 vchiq_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
vchiq_del_timer(struct timer_list * t)125 vchiq_del_timer(struct timer_list *t)
126 {
127 vchiq_del_timer_sync(t);
128 return 0;
129 }
130
131 /*
132 * Completion API
133 */
134 void
init_completion(struct completion * c)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
destroy_completion(struct completion * c)143 destroy_completion(struct completion *c)
144 {
145 cv_destroy(&c->cv);
146 mtx_destroy(&c->lock);
147 }
148
149 void
complete(struct completion * c)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
complete_all(struct completion * c)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
INIT_COMPLETION_locked(struct completion * c)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
_completion_claim(struct completion * c)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
wait_for_completion(struct completion * c)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
try_wait_for_completion(struct completion * c)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
wait_for_completion_interruptible_timeout(struct completion * c,unsigned long timeout)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
wait_for_completion_interruptible(struct completion * c)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
wait_for_completion_killable(struct completion * c)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
sema_sysinit(void * arg)299 void sema_sysinit(void *arg)
300 {
301 struct semaphore *s = arg;
302
303 _sema_init(s, 1);
304 }
305
306 void
_sema_init(struct semaphore * s,int value)307 _sema_init(struct semaphore *s, int value)
308 {
309 bzero(s, sizeof(*s));
310 mtx_init(&s->mtx, "sema lock", "VCHIQ sepmaphore backing lock",
311 MTX_DEF | MTX_NOWITNESS | MTX_QUIET);
312 cv_init(&s->cv, "sema cv");
313 s->value = value;
314 }
315
316 void
_sema_destroy(struct semaphore * s)317 _sema_destroy(struct semaphore *s)
318 {
319 mtx_destroy(&s->mtx);
320 cv_destroy(&s->cv);
321 }
322
323 void
down(struct semaphore * s)324 down(struct semaphore *s)
325 {
326
327 mtx_lock(&s->mtx);
328 while (s->value == 0) {
329 s->waiters++;
330 cv_wait(&s->cv, &s->mtx);
331 s->waiters--;
332 }
333
334 s->value--;
335 mtx_unlock(&s->mtx);
336 }
337
338 int
down_interruptible(struct semaphore * s)339 down_interruptible(struct semaphore *s)
340 {
341 int ret ;
342
343 ret = 0;
344
345 mtx_lock(&s->mtx);
346
347 while (s->value == 0) {
348 s->waiters++;
349 ret = cv_wait_sig(&s->cv, &s->mtx);
350 s->waiters--;
351
352 if (ret == EINTR) {
353 mtx_unlock(&s->mtx);
354 return (-EINTR);
355 }
356
357 if (ret == ERESTART)
358 continue;
359 }
360
361 s->value--;
362 mtx_unlock(&s->mtx);
363
364 return (0);
365 }
366
367 int
down_trylock(struct semaphore * s)368 down_trylock(struct semaphore *s)
369 {
370 int ret;
371
372 ret = 0;
373
374 mtx_lock(&s->mtx);
375
376 if (s->value > 0) {
377 /* Success. */
378 s->value--;
379 ret = 0;
380 } else {
381 ret = -EAGAIN;
382 }
383
384 mtx_unlock(&s->mtx);
385
386 return (ret);
387 }
388
389 void
up(struct semaphore * s)390 up(struct semaphore *s)
391 {
392 mtx_lock(&s->mtx);
393 s->value++;
394 if (s->waiters && s->value > 0)
395 cv_signal(&s->cv);
396
397 mtx_unlock(&s->mtx);
398 }
399
400 /*
401 * Logging API
402 */
403 void
rlprintf(int pps,const char * fmt,...)404 rlprintf(int pps, const char *fmt, ...)
405 {
406 va_list ap;
407 static struct timeval last_printf;
408 static int count;
409
410 if (ppsratecheck(&last_printf, &count, pps)) {
411 va_start(ap, fmt);
412 vprintf(fmt, ap);
413 va_end(ap);
414 }
415 }
416
417 void
device_rlprintf(int pps,device_t dev,const char * fmt,...)418 device_rlprintf(int pps, device_t dev, const char *fmt, ...)
419 {
420 va_list ap;
421 static struct timeval last_printf;
422 static int count;
423
424 if (ppsratecheck(&last_printf, &count, pps)) {
425 va_start(ap, fmt);
426 device_print_prettyname(dev);
427 vprintf(fmt, ap);
428 va_end(ap);
429 }
430 }
431
432 /*
433 * Signals API
434 */
435
436 void
flush_signals(VCHIQ_THREAD_T thr)437 flush_signals(VCHIQ_THREAD_T thr)
438 {
439 printf("Implement ME: %s\n", __func__);
440 }
441
442 int
fatal_signal_pending(VCHIQ_THREAD_T thr)443 fatal_signal_pending(VCHIQ_THREAD_T thr)
444 {
445 printf("Implement ME: %s\n", __func__);
446 return (0);
447 }
448
449 /*
450 * kthread API
451 */
452
453 /*
454 * This is a hack to avoid memory leak
455 */
456 #define MAX_THREAD_DATA_SLOTS 32
457 static int thread_data_slot = 0;
458
459 struct thread_data {
460 void *data;
461 int (*threadfn)(void *);
462 };
463
464 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
465
466 static void
kthread_wrapper(void * data)467 kthread_wrapper(void *data)
468 {
469 struct thread_data *slot;
470
471 slot = data;
472 slot->threadfn(slot->data);
473 }
474
475 VCHIQ_THREAD_T
vchiq_thread_create(int (* threadfn)(void * data),void * data,const char namefmt[],...)476 vchiq_thread_create(int (*threadfn)(void *data),
477 void *data,
478 const char namefmt[], ...)
479 {
480 VCHIQ_THREAD_T newp;
481 va_list ap;
482 char name[MAXCOMLEN+1];
483 struct thread_data *slot;
484
485 if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) {
486 printf("kthread_create: out of thread data slots\n");
487 return (NULL);
488 }
489
490 slot = &thread_slots[thread_data_slot];
491 slot->data = data;
492 slot->threadfn = threadfn;
493
494 va_start(ap, namefmt);
495 vsnprintf(name, sizeof(name), namefmt, ap);
496 va_end(ap);
497
498 newp = NULL;
499 if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0,
500 "%s", name) != 0) {
501 /* Just to be sure */
502 newp = NULL;
503 }
504 else
505 thread_data_slot++;
506
507 return newp;
508 }
509
510 void
set_user_nice(VCHIQ_THREAD_T thr,int nice)511 set_user_nice(VCHIQ_THREAD_T thr, int nice)
512 {
513 /* NOOP */
514 }
515
516 void
wake_up_process(VCHIQ_THREAD_T thr)517 wake_up_process(VCHIQ_THREAD_T thr)
518 {
519 /* NOOP */
520 }
521
522 void
bcm_mbox_write(int channel,uint32_t data)523 bcm_mbox_write(int channel, uint32_t data)
524 {
525 device_t mbox;
526
527 mbox = devclass_get_device(devclass_find("mbox"), 0);
528
529 if (mbox)
530 MBOX_WRITE(mbox, channel, data);
531 }
532