1 1.1 jmcneill /*- 2 1.1 jmcneill * Copyright (c) 2010 Max Khon <fjoe (at) freebsd.org> 3 1.1 jmcneill * All rights reserved. 4 1.1 jmcneill * 5 1.1 jmcneill * This software was developed by Max Khon under sponsorship from 6 1.1 jmcneill * the FreeBSD Foundation and Ethon Technologies GmbH. 7 1.1 jmcneill * 8 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 9 1.1 jmcneill * modification, are permitted provided that the following conditions 10 1.1 jmcneill * are met: 11 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 12 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 13 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 15 1.1 jmcneill * documentation and/or other materials provided with the distribution. 16 1.1 jmcneill * 17 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 1.1 jmcneill * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 1.1 jmcneill * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 1.1 jmcneill * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 1.1 jmcneill * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 jmcneill * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 1.1 jmcneill * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 1.1 jmcneill * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 1.1 jmcneill * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 1.1 jmcneill * SUCH DAMAGE. 28 1.1 jmcneill * 29 1.10 skrll * $Id: vchi_bsd.c,v 1.10 2017/11/05 09:11:43 skrll Exp $ 30 1.1 jmcneill */ 31 1.1 jmcneill 32 1.1 jmcneill #include <sys/types.h> 33 1.1 jmcneill #include <sys/bus.h> 34 1.1 jmcneill #include <sys/callout.h> 35 1.1 jmcneill #include <sys/param.h> 36 1.1 jmcneill #include <sys/proc.h> 37 1.1 jmcneill #include <sys/systm.h> 38 1.1 jmcneill 39 1.1 jmcneill #include <interface/compat/vchi_bsd.h> 40 1.1 jmcneill 41 1.1 jmcneill MALLOC_DEFINE(M_VCHI, "VCHI", "VCHI"); 42 1.1 jmcneill 43 1.1 jmcneill /* 44 1.1 jmcneill * Timer API 45 1.1 jmcneill */ 46 1.1 jmcneill static void 47 1.1 jmcneill run_timer(void *arg) 48 1.1 jmcneill { 49 1.1 jmcneill struct timer_list *t = (struct timer_list *) arg; 50 1.1 jmcneill void (*function)(unsigned long); 51 1.1 jmcneill 52 1.1 jmcneill spin_lock(&t->mtx); 53 1.1 jmcneill if (callout_pending(&t->callout)) { 54 1.1 jmcneill /* callout was reset */ 55 1.1 jmcneill spin_unlock(&t->mtx); 56 1.1 jmcneill return; 57 1.1 jmcneill } 58 1.1 jmcneill if (!callout_active(&t->callout)) { 59 1.1 jmcneill /* callout was stopped */ 60 1.1 jmcneill spin_unlock(&t->mtx); 61 1.1 jmcneill return; 62 1.1 jmcneill } 63 1.1 jmcneill callout_ack(&t->callout); 64 1.1 jmcneill 65 1.1 jmcneill function = t->function; 66 1.1 jmcneill spin_unlock(&t->mtx); 67 1.1 jmcneill 68 1.1 jmcneill function(t->data); 69 1.1 jmcneill } 70 1.1 jmcneill 71 1.1 jmcneill void 72 1.1 jmcneill init_timer(struct timer_list *t) 73 1.1 jmcneill { 74 1.1 jmcneill spin_lock_init(&t->mtx); 75 1.1 jmcneill callout_init(&t->callout, CALLOUT_MPSAFE); 76 1.1 jmcneill t->expires = 0; 77 1.1 jmcneill /* 78 1.1 jmcneill * function and data are not initialized intentionally: 79 1.1 jmcneill * they are not initialized by Linux implementation too 80 1.1 jmcneill */ 81 1.1 jmcneill } 82 1.1 jmcneill 83 1.1 jmcneill void 84 1.1 jmcneill setup_timer(struct timer_list *t, void (*function)(unsigned long), unsigned long data) 85 1.1 jmcneill { 86 1.1 jmcneill t->function = function; 87 1.1 jmcneill t->data = data; 88 1.1 jmcneill init_timer(t); 89 1.1 jmcneill } 90 1.1 jmcneill 91 1.1 jmcneill void 92 1.1 jmcneill mod_timer(struct timer_list *t, unsigned long expires) 93 1.1 jmcneill { 94 1.1 jmcneill spin_lock(&t->mtx); 95 1.1 jmcneill callout_reset(&t->callout, expires - jiffies, run_timer, t); 96 1.1 jmcneill spin_unlock(&t->mtx); 97 1.1 jmcneill } 98 1.1 jmcneill 99 1.1 jmcneill void 100 1.1 jmcneill add_timer(struct timer_list *t) 101 1.1 jmcneill { 102 1.1 jmcneill mod_timer(t, t->expires); 103 1.1 jmcneill } 104 1.1 jmcneill 105 1.1 jmcneill int 106 1.1 jmcneill del_timer_sync(struct timer_list *t) 107 1.1 jmcneill { 108 1.1 jmcneill spin_lock(&t->mtx); 109 1.9 jmcneill callout_halt(&t->callout, &t->mtx); 110 1.1 jmcneill spin_unlock(&t->mtx); 111 1.1 jmcneill 112 1.1 jmcneill spin_lock_destroy(&t->mtx); 113 1.1 jmcneill return 0; 114 1.1 jmcneill } 115 1.1 jmcneill 116 1.1 jmcneill int 117 1.1 jmcneill del_timer(struct timer_list *t) 118 1.1 jmcneill { 119 1.1 jmcneill del_timer_sync(t); 120 1.1 jmcneill return 0; 121 1.1 jmcneill } 122 1.1 jmcneill 123 1.1 jmcneill /* 124 1.1 jmcneill * Semaphore API 125 1.1 jmcneill */ 126 1.1 jmcneill 127 1.1 jmcneill void sema_sysinit(void *arg) 128 1.1 jmcneill { 129 1.1 jmcneill struct semaphore *s = arg; 130 1.1 jmcneill 131 1.1 jmcneill printf("sema_sysinit\n"); 132 1.1 jmcneill _sema_init(s, 1); 133 1.1 jmcneill } 134 1.1 jmcneill 135 1.1 jmcneill void 136 1.1 jmcneill _sema_init(struct semaphore *s, int value) 137 1.1 jmcneill { 138 1.4 skrll memset(s, 0, sizeof(*s)); 139 1.10 skrll mutex_init(&s->mtx, MUTEX_DEFAULT, IPL_VM); 140 1.3 skrll cv_init(&s->cv, "semacv"); 141 1.1 jmcneill s->value = value; 142 1.1 jmcneill } 143 1.1 jmcneill 144 1.1 jmcneill void 145 1.1 jmcneill _sema_destroy(struct semaphore *s) 146 1.1 jmcneill { 147 1.1 jmcneill mutex_destroy(&s->mtx); 148 1.1 jmcneill cv_destroy(&s->cv); 149 1.1 jmcneill } 150 1.1 jmcneill 151 1.1 jmcneill void 152 1.1 jmcneill down(struct semaphore *s) 153 1.1 jmcneill { 154 1.1 jmcneill 155 1.1 jmcneill mutex_enter(&s->mtx); 156 1.1 jmcneill while (s->value == 0) { 157 1.1 jmcneill s->waiters++; 158 1.1 jmcneill cv_wait(&s->cv, &s->mtx); 159 1.1 jmcneill s->waiters--; 160 1.1 jmcneill } 161 1.1 jmcneill 162 1.1 jmcneill s->value--; 163 1.1 jmcneill mutex_exit(&s->mtx); 164 1.1 jmcneill } 165 1.1 jmcneill 166 1.1 jmcneill int 167 1.1 jmcneill down_interruptible(struct semaphore *s) 168 1.1 jmcneill { 169 1.1 jmcneill 170 1.1 jmcneill mutex_enter(&s->mtx); 171 1.1 jmcneill 172 1.1 jmcneill while (s->value == 0) { 173 1.1 jmcneill s->waiters++; 174 1.6 skrll int ret = cv_wait_sig(&s->cv, &s->mtx); 175 1.1 jmcneill s->waiters--; 176 1.1 jmcneill 177 1.1 jmcneill if (ret == EINTR || ret == ERESTART) { 178 1.1 jmcneill mutex_exit(&s->mtx); 179 1.5 skrll return -EINTR; 180 1.1 jmcneill } 181 1.1 jmcneill } 182 1.1 jmcneill 183 1.1 jmcneill s->value--; 184 1.1 jmcneill mutex_exit(&s->mtx); 185 1.1 jmcneill 186 1.5 skrll return 0; 187 1.1 jmcneill } 188 1.1 jmcneill 189 1.1 jmcneill int 190 1.1 jmcneill down_trylock(struct semaphore *s) 191 1.1 jmcneill { 192 1.6 skrll int ret = 1; 193 1.1 jmcneill 194 1.1 jmcneill mutex_enter(&s->mtx); 195 1.1 jmcneill 196 1.1 jmcneill if (s->value > 0) { 197 1.1 jmcneill /* Success. */ 198 1.1 jmcneill s->value--; 199 1.1 jmcneill ret = 0; 200 1.1 jmcneill } 201 1.1 jmcneill 202 1.1 jmcneill mutex_exit(&s->mtx); 203 1.1 jmcneill 204 1.5 skrll return ret; 205 1.1 jmcneill } 206 1.1 jmcneill 207 1.1 jmcneill void 208 1.1 jmcneill up(struct semaphore *s) 209 1.1 jmcneill { 210 1.1 jmcneill mutex_enter(&s->mtx); 211 1.1 jmcneill s->value++; 212 1.6 skrll if (s->value > 0 && s->waiters) 213 1.1 jmcneill cv_signal(&s->cv); 214 1.1 jmcneill 215 1.1 jmcneill mutex_exit(&s->mtx); 216 1.1 jmcneill } 217 1.1 jmcneill 218 1.1 jmcneill /* 219 1.1 jmcneill * Logging API 220 1.1 jmcneill */ 221 1.1 jmcneill void 222 1.1 jmcneill rlprintf(int pps, const char *fmt, ...) 223 1.1 jmcneill { 224 1.1 jmcneill va_list ap; 225 1.1 jmcneill static struct timeval last_printf; 226 1.1 jmcneill static int count; 227 1.1 jmcneill 228 1.1 jmcneill if (ppsratecheck(&last_printf, &count, pps)) { 229 1.1 jmcneill va_start(ap, fmt); 230 1.1 jmcneill vprintf(fmt, ap); 231 1.1 jmcneill va_end(ap); 232 1.1 jmcneill } 233 1.1 jmcneill } 234 1.1 jmcneill 235 1.1 jmcneill void 236 1.1 jmcneill device_rlprintf(int pps, device_t dev, const char *fmt, ...) 237 1.1 jmcneill { 238 1.1 jmcneill va_list ap; 239 1.1 jmcneill static struct timeval last_printf; 240 1.1 jmcneill static int count; 241 1.1 jmcneill 242 1.1 jmcneill if (ppsratecheck(&last_printf, &count, pps)) { 243 1.1 jmcneill va_start(ap, fmt); 244 1.1 jmcneill device_print_prettyname(dev); 245 1.1 jmcneill vprintf(fmt, ap); 246 1.1 jmcneill va_end(ap); 247 1.1 jmcneill } 248 1.1 jmcneill } 249 1.1 jmcneill 250 1.1 jmcneill /* 251 1.1 jmcneill * Signals API 252 1.1 jmcneill */ 253 1.1 jmcneill 254 1.1 jmcneill void 255 1.1 jmcneill flush_signals(VCHIQ_THREAD_T thr) 256 1.1 jmcneill { 257 1.1 jmcneill printf("Implement ME: %s\n", __func__); 258 1.1 jmcneill } 259 1.1 jmcneill 260 1.1 jmcneill int 261 1.1 jmcneill fatal_signal_pending(VCHIQ_THREAD_T thr) 262 1.1 jmcneill { 263 1.1 jmcneill printf("Implement ME: %s\n", __func__); 264 1.5 skrll return 0; 265 1.1 jmcneill } 266 1.1 jmcneill 267 1.1 jmcneill /* 268 1.1 jmcneill * kthread API 269 1.1 jmcneill */ 270 1.1 jmcneill 271 1.1 jmcneill /* 272 1.1 jmcneill * This is a hack to avoid memory leak 273 1.1 jmcneill */ 274 1.1 jmcneill #define MAX_THREAD_DATA_SLOTS 32 275 1.1 jmcneill static int thread_data_slot = 0; 276 1.1 jmcneill 277 1.1 jmcneill struct thread_data { 278 1.1 jmcneill void *data; 279 1.1 jmcneill int (*threadfn)(void *); 280 1.1 jmcneill }; 281 1.1 jmcneill 282 1.1 jmcneill static struct thread_data thread_slots[MAX_THREAD_DATA_SLOTS]; 283 1.1 jmcneill 284 1.8 skrll static void 285 1.1 jmcneill kthread_wrapper(void *data) 286 1.1 jmcneill { 287 1.1 jmcneill struct thread_data *slot; 288 1.1 jmcneill 289 1.1 jmcneill slot = data; 290 1.1 jmcneill slot->threadfn(slot->data); 291 1.1 jmcneill } 292 1.1 jmcneill 293 1.1 jmcneill VCHIQ_THREAD_T 294 1.1 jmcneill vchiq_thread_create(int (*threadfn)(void *data), 295 1.1 jmcneill void *data, 296 1.1 jmcneill const char namefmt[], ...) 297 1.1 jmcneill { 298 1.1 jmcneill VCHIQ_THREAD_T newt; 299 1.1 jmcneill va_list ap; 300 1.1 jmcneill char name[MAXCOMLEN+1]; 301 1.1 jmcneill struct thread_data *slot; 302 1.1 jmcneill 303 1.1 jmcneill if (thread_data_slot >= MAX_THREAD_DATA_SLOTS) { 304 1.1 jmcneill printf("kthread_create: out of thread data slots\n"); 305 1.5 skrll return NULL; 306 1.1 jmcneill } 307 1.1 jmcneill 308 1.1 jmcneill slot = &thread_slots[thread_data_slot]; 309 1.1 jmcneill slot->data = data; 310 1.1 jmcneill slot->threadfn = threadfn; 311 1.1 jmcneill 312 1.1 jmcneill va_start(ap, namefmt); 313 1.1 jmcneill vsnprintf(name, sizeof(name), namefmt, ap); 314 1.1 jmcneill va_end(ap); 315 1.8 skrll 316 1.1 jmcneill newt = NULL; 317 1.9 jmcneill if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, kthread_wrapper, 318 1.9 jmcneill slot, &newt, "%s", name) != 0) { 319 1.1 jmcneill /* Just to be sure */ 320 1.1 jmcneill newt = NULL; 321 1.1 jmcneill } else { 322 1.1 jmcneill thread_data_slot++; 323 1.1 jmcneill } 324 1.1 jmcneill 325 1.1 jmcneill return newt; 326 1.1 jmcneill } 327 1.1 jmcneill 328 1.1 jmcneill void 329 1.1 jmcneill set_user_nice(VCHIQ_THREAD_T thr, int nice) 330 1.1 jmcneill { 331 1.1 jmcneill /* NOOP */ 332 1.1 jmcneill } 333 1.1 jmcneill 334 1.1 jmcneill void 335 1.1 jmcneill wake_up_process(VCHIQ_THREAD_T thr) 336 1.1 jmcneill { 337 1.1 jmcneill /* NOOP */ 338 1.1 jmcneill } 339