]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/vchiq/interface/compat/vchi_bsd.c
MFV r353606: 10067 Miscellaneous man page typos
[FreeBSD/FreeBSD.git] / sys / contrib / vchiq / interface / compat / vchi_bsd.c
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
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
80 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
92 setup_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
99 void
100 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
108 add_timer(struct timer_list *t)
109 {
110         mod_timer(t, t->expires);
111 }
112
113 int
114 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
125 del_timer(struct timer_list *t)
126 {
127         del_timer_sync(t);
128         return 0;
129 }
130
131 /*
132  * Completion API
133  */
134 void
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
143 destroy_completion(struct completion *c)
144 {
145         cv_destroy(&c->cv);
146         mtx_destroy(&c->lock);
147 }
148
149 void
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
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
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
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
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
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
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
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
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
299 void sema_sysinit(void *arg)
300 {
301         struct semaphore *s = arg;
302
303         _sema_init(s, 1);
304 }
305
306 void
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
317 _sema_destroy(struct semaphore *s)
318 {
319         mtx_destroy(&s->mtx);
320         cv_destroy(&s->cv);
321 }
322
323 void
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
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
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
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
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
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
437 flush_signals(VCHIQ_THREAD_T thr)
438 {
439         printf("Implement ME: %s\n", __func__);
440 }
441
442 int
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
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
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
511 set_user_nice(VCHIQ_THREAD_T thr, int nice)
512 {
513         /* NOOP */
514 }
515
516 void
517 wake_up_process(VCHIQ_THREAD_T thr)
518 {
519         /* NOOP */
520 }
521
522 void
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 }