Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/vchiq/interface/compat/vchi_bsd.c
48383 views
1
/*-
2
* Copyright (c) 2010 Max Khon <[email protected]>
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/stdarg.h>
40
#include <sys/syscallsubr.h>
41
#include <sys/systm.h>
42
#include <sys/taskqueue.h>
43
44
#include "mbox_if.h"
45
46
#include <interface/compat/vchi_bsd.h>
47
48
MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI");
49
50
/*
51
* Timer API
52
*/
53
static void
54
run_timer(void *arg)
55
{
56
struct timer_list *t = (struct timer_list *) arg;
57
void (*function)(unsigned long);
58
59
mtx_lock_spin(&t->mtx);
60
if (callout_pending(&t->callout)) {
61
/* callout was reset */
62
mtx_unlock_spin(&t->mtx);
63
return;
64
}
65
if (!callout_active(&t->callout)) {
66
/* callout was stopped */
67
mtx_unlock_spin(&t->mtx);
68
return;
69
}
70
callout_deactivate(&t->callout);
71
72
function = t->function;
73
mtx_unlock_spin(&t->mtx);
74
75
function(t->data);
76
}
77
78
void
79
vchiq_init_timer(struct timer_list *t)
80
{
81
mtx_init(&t->mtx, "dahdi timer lock", NULL, MTX_SPIN);
82
callout_init(&t->callout, 1);
83
t->expires = 0;
84
/*
85
* function and data are not initialized intentionally:
86
* they are not initialized by Linux implementation too
87
*/
88
}
89
90
void
91
vchiq_setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data)
92
{
93
t->function = function;
94
t->data = data;
95
vchiq_init_timer(t);
96
}
97
98
void
99
vchiq_mod_timer(struct timer_list *t, unsigned long expires)
100
{
101
mtx_lock_spin(&t->mtx);
102
callout_reset(&t->callout, expires - jiffies, run_timer, t);
103
mtx_unlock_spin(&t->mtx);
104
}
105
106
void
107
vchiq_add_timer(struct timer_list *t)
108
{
109
vchiq_mod_timer(t, t->expires);
110
}
111
112
int
113
vchiq_del_timer_sync(struct timer_list *t)
114
{
115
mtx_lock_spin(&t->mtx);
116
callout_stop(&t->callout);
117
mtx_unlock_spin(&t->mtx);
118
119
mtx_destroy(&t->mtx);
120
return 0;
121
}
122
123
int
124
vchiq_del_timer(struct timer_list *t)
125
{
126
vchiq_del_timer_sync(t);
127
return 0;
128
}
129
130
/*
131
* Completion API
132
*/
133
void
134
init_completion(struct completion *c)
135
{
136
cv_init(&c->cv, "VCHI completion cv");
137
mtx_init(&c->lock, "VCHI completion lock", "condvar", MTX_DEF);
138
c->done = 0;
139
}
140
141
void
142
destroy_completion(struct completion *c)
143
{
144
cv_destroy(&c->cv);
145
mtx_destroy(&c->lock);
146
}
147
148
void
149
complete(struct completion *c)
150
{
151
mtx_lock(&c->lock);
152
153
if (c->done >= 0) {
154
KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */
155
c->done++;
156
cv_signal(&c->cv);
157
} else {
158
KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
159
}
160
161
mtx_unlock(&c->lock);
162
}
163
164
void
165
complete_all(struct completion *c)
166
{
167
mtx_lock(&c->lock);
168
169
if (c->done >= 0) {
170
KASSERT(c->done < INT_MAX, ("c->done overflow")); /* XXX check */
171
c->done = -1;
172
cv_broadcast(&c->cv);
173
} else {
174
KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
175
}
176
177
mtx_unlock(&c->lock);
178
}
179
180
void
181
INIT_COMPLETION_locked(struct completion *c)
182
{
183
mtx_lock(&c->lock);
184
185
c->done = 0;
186
187
mtx_unlock(&c->lock);
188
}
189
190
static void
191
_completion_claim(struct completion *c)
192
{
193
194
KASSERT(mtx_owned(&c->lock),
195
("_completion_claim should be called with acquired lock"));
196
KASSERT(c->done != 0, ("_completion_claim on non-waited completion"));
197
if (c->done > 0)
198
c->done--;
199
else
200
KASSERT(c->done == -1, ("Invalid value of c->done: %d", c->done));
201
}
202
203
void
204
wait_for_completion(struct completion *c)
205
{
206
mtx_lock(&c->lock);
207
if (!c->done)
208
cv_wait(&c->cv, &c->lock);
209
c->done--;
210
mtx_unlock(&c->lock);
211
}
212
213
int
214
try_wait_for_completion(struct completion *c)
215
{
216
int res = 0;
217
218
mtx_lock(&c->lock);
219
if (!c->done)
220
res = 1;
221
else
222
c->done--;
223
mtx_unlock(&c->lock);
224
return res == 0;
225
}
226
227
int
228
wait_for_completion_interruptible_timeout(struct completion *c, unsigned long timeout)
229
{
230
int res = 0;
231
unsigned long start, now;
232
start = jiffies;
233
234
mtx_lock(&c->lock);
235
while (c->done == 0) {
236
res = cv_timedwait_sig(&c->cv, &c->lock, timeout);
237
if (res)
238
goto out;
239
now = jiffies;
240
if (timeout < (now - start)) {
241
res = EWOULDBLOCK;
242
goto out;
243
}
244
245
timeout -= (now - start);
246
start = now;
247
}
248
249
_completion_claim(c);
250
res = 0;
251
252
out:
253
mtx_unlock(&c->lock);
254
255
if (res == EWOULDBLOCK) {
256
return 0;
257
} else if ((res == EINTR) || (res == ERESTART)) {
258
return -ERESTART;
259
} else {
260
KASSERT((res == 0), ("res = %d", res));
261
return timeout;
262
}
263
}
264
265
int
266
wait_for_completion_interruptible(struct completion *c)
267
{
268
int res = 0;
269
270
mtx_lock(&c->lock);
271
while (c->done == 0) {
272
res = cv_wait_sig(&c->cv, &c->lock);
273
if (res)
274
goto out;
275
}
276
277
_completion_claim(c);
278
279
out:
280
mtx_unlock(&c->lock);
281
282
if ((res == EINTR) || (res == ERESTART))
283
res = -ERESTART;
284
return res;
285
}
286
287
int
288
wait_for_completion_killable(struct completion *c)
289
{
290
291
return wait_for_completion_interruptible(c);
292
}
293
294
/*
295
* Semaphore API
296
*/
297
298
void sema_sysinit(void *arg)
299
{
300
struct semaphore *s = arg;
301
302
_sema_init(s, 1);
303
}
304
305
void
306
_sema_init(struct semaphore *s, int value)
307
{
308
bzero(s, sizeof(*s));
309
mtx_init(&s->mtx, "sema lock", "VCHIQ sepmaphore backing lock",
310
MTX_DEF | MTX_NOWITNESS | MTX_QUIET);
311
cv_init(&s->cv, "sema cv");
312
s->value = value;
313
}
314
315
void
316
_sema_destroy(struct semaphore *s)
317
{
318
mtx_destroy(&s->mtx);
319
cv_destroy(&s->cv);
320
}
321
322
void
323
down(struct semaphore *s)
324
{
325
326
mtx_lock(&s->mtx);
327
while (s->value == 0) {
328
s->waiters++;
329
cv_wait(&s->cv, &s->mtx);
330
s->waiters--;
331
}
332
333
s->value--;
334
mtx_unlock(&s->mtx);
335
}
336
337
int
338
down_interruptible(struct semaphore *s)
339
{
340
int ret ;
341
342
ret = 0;
343
344
mtx_lock(&s->mtx);
345
346
while (s->value == 0) {
347
s->waiters++;
348
ret = cv_wait_sig(&s->cv, &s->mtx);
349
s->waiters--;
350
351
if (ret == EINTR) {
352
mtx_unlock(&s->mtx);
353
return (-EINTR);
354
}
355
356
if (ret == ERESTART)
357
continue;
358
}
359
360
s->value--;
361
mtx_unlock(&s->mtx);
362
363
return (0);
364
}
365
366
int
367
down_trylock(struct semaphore *s)
368
{
369
int ret;
370
371
ret = 0;
372
373
mtx_lock(&s->mtx);
374
375
if (s->value > 0) {
376
/* Success. */
377
s->value--;
378
ret = 0;
379
} else {
380
ret = -EAGAIN;
381
}
382
383
mtx_unlock(&s->mtx);
384
385
return (ret);
386
}
387
388
void
389
up(struct semaphore *s)
390
{
391
mtx_lock(&s->mtx);
392
s->value++;
393
if (s->waiters && s->value > 0)
394
cv_signal(&s->cv);
395
396
mtx_unlock(&s->mtx);
397
}
398
399
/*
400
* Logging API
401
*/
402
void
403
rlprintf(int pps, const char *fmt, ...)
404
{
405
va_list ap;
406
static struct timeval last_printf;
407
static int count;
408
409
if (ppsratecheck(&last_printf, &count, pps)) {
410
va_start(ap, fmt);
411
vprintf(fmt, ap);
412
va_end(ap);
413
}
414
}
415
416
void
417
device_rlprintf(int pps, device_t dev, const char *fmt, ...)
418
{
419
va_list ap;
420
static struct timeval last_printf;
421
static int count;
422
423
if (ppsratecheck(&last_printf, &count, pps)) {
424
va_start(ap, fmt);
425
device_print_prettyname(dev);
426
vprintf(fmt, ap);
427
va_end(ap);
428
}
429
}
430
431
/*
432
* Signals API
433
*/
434
435
void
436
flush_signals(VCHIQ_THREAD_T thr)
437
{
438
printf("Implement ME: %s\n", __func__);
439
}
440
441
int
442
fatal_signal_pending(VCHIQ_THREAD_T thr)
443
{
444
printf("Implement ME: %s\n", __func__);
445
return (0);
446
}
447
448
/*
449
* kthread API
450
*/
451
452
/*
453
* This is a hack to avoid memory leak
454
*/
455
#define MAX_THREAD_DATA_SLOTS 32
456
static int thread_data_slot = 0;
457
458
struct thread_data {
459
void *data;
460
int (*threadfn)(void *);
461
};
462
463
static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
464
465
static void
466
kthread_wrapper(void *data)
467
{
468
struct thread_data *slot;
469
470
slot = data;
471
slot->threadfn(slot->data);
472
}
473
474
VCHIQ_THREAD_T
475
vchiq_thread_create(int (*threadfn)(void *data),
476
void *data,
477
const char namefmt[], ...)
478
{
479
VCHIQ_THREAD_T newp;
480
va_list ap;
481
char name[MAXCOMLEN+1];
482
struct thread_data *slot;
483
484
if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) {
485
printf("kthread_create: out of thread data slots\n");
486
return (NULL);
487
}
488
489
slot = &thread_slots[thread_data_slot];
490
slot->data = data;
491
slot->threadfn = threadfn;
492
493
va_start(ap, namefmt);
494
vsnprintf(name, sizeof(name), namefmt, ap);
495
va_end(ap);
496
497
newp = NULL;
498
if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0,
499
"%s", name) != 0) {
500
/* Just to be sure */
501
newp = NULL;
502
}
503
else
504
thread_data_slot++;
505
506
return newp;
507
}
508
509
void
510
set_user_nice(VCHIQ_THREAD_T thr, int nice)
511
{
512
/* NOOP */
513
}
514
515
void
516
wake_up_process(VCHIQ_THREAD_T thr)
517
{
518
/* NOOP */
519
}
520
521
void
522
bcm_mbox_write(int channel, uint32_t data)
523
{
524
device_t mbox;
525
526
mbox = devclass_get_device(devclass_find("mbox"), 0);
527
528
if (mbox)
529
MBOX_WRITE(mbox, channel, data);
530
}
531
532