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
107442 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
mtx_lock(&s->mtx);
344
345
while (s->value == 0) {
346
s->waiters++;
347
ret = cv_wait_sig(&s->cv, &s->mtx);
348
s->waiters--;
349
350
/* XXXMDC As per its semaphore.c, linux can only return EINTR */
351
if (ret) {
352
mtx_unlock(&s->mtx);
353
return -EINTR;
354
}
355
}
356
357
s->value--;
358
mtx_unlock(&s->mtx);
359
360
return (0);
361
}
362
363
int
364
down_trylock(struct semaphore *s)
365
{
366
int ret;
367
368
ret = 0;
369
370
mtx_lock(&s->mtx);
371
372
if (s->value > 0) {
373
/* Success. */
374
s->value--;
375
ret = 0;
376
} else {
377
ret = -EAGAIN;
378
}
379
380
mtx_unlock(&s->mtx);
381
382
return (ret);
383
}
384
385
void
386
up(struct semaphore *s)
387
{
388
mtx_lock(&s->mtx);
389
s->value++;
390
if (s->waiters && s->value > 0)
391
cv_signal(&s->cv);
392
393
mtx_unlock(&s->mtx);
394
}
395
396
/*
397
* Logging API
398
*/
399
void
400
rlprintf(int pps, const char *fmt, ...)
401
{
402
va_list ap;
403
static struct timeval last_printf;
404
static int count;
405
406
if (ppsratecheck(&last_printf, &count, pps)) {
407
va_start(ap, fmt);
408
vprintf(fmt, ap);
409
va_end(ap);
410
}
411
}
412
413
void
414
device_rlprintf(int pps, device_t dev, const char *fmt, ...)
415
{
416
va_list ap;
417
static struct timeval last_printf;
418
static int count;
419
420
if (ppsratecheck(&last_printf, &count, pps)) {
421
va_start(ap, fmt);
422
device_print_prettyname(dev);
423
vprintf(fmt, ap);
424
va_end(ap);
425
}
426
}
427
428
/*
429
* Signals API
430
*/
431
432
void
433
flush_signals(VCHIQ_THREAD_T thr)
434
{
435
printf("Implement ME: %s\n", __func__);
436
}
437
438
int
439
fatal_signal_pending(VCHIQ_THREAD_T thr)
440
{
441
return (curproc_sigkilled());
442
}
443
444
/*
445
* kthread API
446
*/
447
448
/*
449
* This is a hack to avoid memory leak
450
*/
451
#define MAX_THREAD_DATA_SLOTS 32
452
static int thread_data_slot = 0;
453
454
struct thread_data {
455
void *data;
456
int (*threadfn)(void *);
457
};
458
459
static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS];
460
461
static void
462
kthread_wrapper(void *data)
463
{
464
struct thread_data *slot;
465
466
slot = data;
467
slot->threadfn(slot->data);
468
}
469
470
VCHIQ_THREAD_T
471
vchiq_thread_create(int (*threadfn)(void *data),
472
void *data,
473
const char namefmt[], ...)
474
{
475
VCHIQ_THREAD_T newp;
476
va_list ap;
477
char name[MAXCOMLEN+1];
478
struct thread_data *slot;
479
480
if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) {
481
printf("kthread_create: out of thread data slots\n");
482
return (NULL);
483
}
484
485
slot = &thread_slots[thread_data_slot];
486
slot->data = data;
487
slot->threadfn = threadfn;
488
489
va_start(ap, namefmt);
490
vsnprintf(name, sizeof(name), namefmt, ap);
491
va_end(ap);
492
493
newp = NULL;
494
if (kproc_create(kthread_wrapper, (void*)slot, &newp, 0, 0,
495
"%s", name) != 0) {
496
/* Just to be sure */
497
newp = NULL;
498
}
499
else
500
thread_data_slot++;
501
502
return newp;
503
}
504
505
void
506
set_user_nice(VCHIQ_THREAD_T thr, int nice)
507
{
508
/* NOOP */
509
}
510
511
void
512
wake_up_process(VCHIQ_THREAD_T thr)
513
{
514
/* NOOP */
515
}
516
517
void
518
bcm_mbox_write(int channel, uint32_t data)
519
{
520
device_t mbox;
521
522
mbox = devclass_get_device(devclass_find("mbox"), 0);
523
524
if (mbox)
525
MBOX_WRITE(mbox, channel, data);
526
}
527
528