]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/vchiq/interface/compat/vchi_bsd.c
Import VCHI driver for Broadcom's VideoCore IV GPU
[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, CALLOUT_MPSAFE);
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         printf("sema_sysinit\n");
304         _sema_init(s, 1);
305 }
306
307 void
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
317 void
318 _sema_destroy(struct semaphore *s)
319 {
320         mtx_destroy(&s->mtx);
321         cv_destroy(&s->cv);
322 }
323
324 void
325 down(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
339 int
340 down_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
368 int
369 down_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
390 void
391 up(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  */
404 void
405 rlprintf(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
418 void
419 device_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
437 void
438 flush_signals(VCHIQ_THREAD_T thr)
439 {
440         printf("Implement ME: %s\n", __func__);
441 }
442
443 int
444 fatal_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
458 static int thread_data_slot = 0;
459
460 struct thread_data {
461         void *data;
462         int (*threadfn)(void *);
463 };
464
465 static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
466
467 static void
468 kthread_wrapper(void *data)
469 {
470         struct thread_data *slot;
471
472         slot = data;
473         slot->threadfn(slot->data);
474 }
475
476 VCHIQ_THREAD_T
477 vchiq_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
511 void
512 set_user_nice(VCHIQ_THREAD_T thr, int nice)
513 {
514         /* NOOP */
515 }
516
517 void
518 wake_up_process(VCHIQ_THREAD_T thr)
519 {
520         /* NOOP */
521 }
522
523 void
524 bcm_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 }