usb_process.c revision 187994
1/* $FreeBSD: head/sys/dev/usb2/core/usb2_process.c 187994 2009-02-02 00:49:39Z alfred $ */ 2/*- 3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#define USB_DEBUG_VAR usb2_proc_debug 28 29#include <dev/usb2/core/usb2_core.h> 30#include <dev/usb2/core/usb2_process.h> 31#include <dev/usb2/core/usb2_debug.h> 32#include <dev/usb2/core/usb2_util.h> 33 34#include <sys/proc.h> 35#include <sys/kthread.h> 36#include <sys/sched.h> 37 38#if (__FreeBSD_version < 700000) 39#define thread_lock(td) mtx_lock_spin(&sched_lock) 40#define thread_unlock(td) mtx_unlock_spin(&sched_lock) 41#endif 42 43#if (__FreeBSD_version >= 800000) 44#define USB_THREAD_CREATE(f, s, p, ...) \ 45 kproc_create((f), (s), (p), RFHIGHPID, 0, __VA_ARGS__) 46#define USB_THREAD_SUSPEND(p) kproc_suspend(p,0) 47#define USB_THREAD_EXIT(err) kproc_exit(err) 48#else 49#define USB_THREAD_CREATE(f, s, p, ...) \ 50 kthread_create((f), (s), (p), RFHIGHPID, 0, __VA_ARGS__) 51#define USB_THREAD_SUSPEND(p) kthread_suspend(p,0) 52#define USB_THREAD_EXIT(err) kthread_exit(err) 53#endif 54 55#if USB_DEBUG 56static int usb2_proc_debug; 57 58SYSCTL_NODE(_hw_usb2, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process"); 59SYSCTL_INT(_hw_usb2_proc, OID_AUTO, debug, CTLFLAG_RW, &usb2_proc_debug, 0, 60 "Debug level"); 61#endif 62 63/*------------------------------------------------------------------------* 64 * usb2_process 65 * 66 * This function is the USB process dispatcher. 67 *------------------------------------------------------------------------*/ 68static void 69usb2_process(void *arg) 70{ 71 struct usb2_process *up = arg; 72 struct usb2_proc_msg *pm; 73 struct thread *td; 74 75 /* adjust priority */ 76 td = curthread; 77 thread_lock(td); 78 sched_prio(td, up->up_prio); 79 thread_unlock(td); 80 81 mtx_lock(up->up_mtx); 82 83 up->up_curtd = td; 84 85 while (1) { 86 87 if (up->up_gone) { 88 break; 89 } 90 /* 91 * NOTE to reimplementors: dequeueing a command from the 92 * "used" queue and executing it must be atomic, with regard 93 * to the "up_mtx" mutex. That means any attempt to queue a 94 * command by another thread must be blocked until either: 95 * 96 * 1) the command sleeps 97 * 98 * 2) the command returns 99 * 100 * Here is a practical example that shows how this helps 101 * solving a problem: 102 * 103 * Assume that you want to set the baud rate on a USB serial 104 * device. During the programming of the device you don't 105 * want to receive nor transmit any data, because it will be 106 * garbage most likely anyway. The programming of our USB 107 * device takes 20 milliseconds and it needs to call 108 * functions that sleep. 109 * 110 * Non-working solution: Before we queue the programming 111 * command, we stop transmission and reception of data. Then 112 * we queue a programming command. At the end of the 113 * programming command we enable transmission and reception 114 * of data. 115 * 116 * Problem: If a second programming command is queued while the 117 * first one is sleeping, we end up enabling transmission 118 * and reception of data too early. 119 * 120 * Working solution: Before we queue the programming command, 121 * we stop transmission and reception of data. Then we queue 122 * a programming command. Then we queue a second command 123 * that only enables transmission and reception of data. 124 * 125 * Why it works: If a second programming command is queued 126 * while the first one is sleeping, then the queueing of a 127 * second command to enable the data transfers, will cause 128 * the previous one, which is still on the queue, to be 129 * removed from the queue, and re-inserted after the last 130 * baud rate programming command, which then gives the 131 * desired result. 132 */ 133 pm = TAILQ_FIRST(&up->up_qhead); 134 135 if (pm) { 136 DPRINTF("Message pm=%p, cb=%p (enter)\n", 137 pm, pm->pm_callback); 138 139 (pm->pm_callback) (pm); 140 141 if (pm == TAILQ_FIRST(&up->up_qhead)) { 142 /* nothing changed */ 143 TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); 144 pm->pm_qentry.tqe_prev = NULL; 145 } 146 DPRINTF("Message pm=%p (leave)\n", pm); 147 148 continue; 149 } 150 /* end if messages - check if anyone is waiting for sync */ 151 if (up->up_dsleep) { 152 up->up_dsleep = 0; 153 usb2_cv_broadcast(&up->up_drain); 154 } 155 up->up_msleep = 1; 156 usb2_cv_wait(&up->up_cv, up->up_mtx); 157 } 158 159 up->up_ptr = NULL; 160 usb2_cv_signal(&up->up_cv); 161 mtx_unlock(up->up_mtx); 162 163 USB_THREAD_EXIT(0); 164} 165 166/*------------------------------------------------------------------------* 167 * usb2_proc_setup 168 * 169 * This function will create a process using the given "prio" that can 170 * execute callbacks. The mutex pointed to by "p_mtx" will be applied 171 * before calling the callbacks and released after that the callback 172 * has returned. The structure pointed to by "up" is assumed to be 173 * zeroed before this function is called. 174 * 175 * Return values: 176 * 0: success 177 * Else: failure 178 *------------------------------------------------------------------------*/ 179uint8_t 180usb2_proc_setup(struct usb2_process *up, struct mtx *p_mtx, uint8_t prio) 181{ 182 up->up_mtx = p_mtx; 183 up->up_prio = prio; 184 185 TAILQ_INIT(&up->up_qhead); 186 187 usb2_cv_init(&up->up_cv, "wmsg"); 188 usb2_cv_init(&up->up_drain, "dmsg"); 189 190 if (USB_THREAD_CREATE(&usb2_process, up, 191 &up->up_ptr, "usbproc")) { 192 DPRINTFN(0, "Unable to create USB process."); 193 up->up_ptr = NULL; 194 goto error; 195 } 196 return (0); 197 198error: 199 usb2_proc_unsetup(up); 200 return (1); 201} 202 203/*------------------------------------------------------------------------* 204 * usb2_proc_unsetup 205 * 206 * NOTE: If the structure pointed to by "up" is all zero, this 207 * function does nothing. 208 * 209 * NOTE: Messages that are pending on the process queue will not be 210 * removed nor called. 211 *------------------------------------------------------------------------*/ 212void 213usb2_proc_unsetup(struct usb2_process *up) 214{ 215 if (!(up->up_mtx)) { 216 /* not initialised */ 217 return; 218 } 219 usb2_proc_drain(up); 220 221 usb2_cv_destroy(&up->up_cv); 222 usb2_cv_destroy(&up->up_drain); 223 224 /* make sure that we do not enter here again */ 225 up->up_mtx = NULL; 226} 227 228/*------------------------------------------------------------------------* 229 * usb2_proc_msignal 230 * 231 * This function will queue one of the passed USB process messages on 232 * the USB process queue. The first message that is not already queued 233 * will get queued. If both messages are already queued the one queued 234 * last will be removed from the queue and queued in the end. The USB 235 * process mutex must be locked when calling this function. This 236 * function exploits the fact that a process can only do one callback 237 * at a time. The message that was queued is returned. 238 *------------------------------------------------------------------------*/ 239void * 240usb2_proc_msignal(struct usb2_process *up, void *_pm0, void *_pm1) 241{ 242 struct usb2_proc_msg *pm0 = _pm0; 243 struct usb2_proc_msg *pm1 = _pm1; 244 struct usb2_proc_msg *pm2; 245 uint32_t d; 246 uint8_t t; 247 248 mtx_assert(up->up_mtx, MA_OWNED); 249 250 t = 0; 251 252 if (pm0->pm_qentry.tqe_prev) { 253 t |= 1; 254 } 255 if (pm1->pm_qentry.tqe_prev) { 256 t |= 2; 257 } 258 if (t == 0) { 259 /* 260 * No entries are queued. Queue "pm0" and use the existing 261 * message number. 262 */ 263 pm2 = pm0; 264 } else if (t == 1) { 265 /* Check if we need to increment the message number. */ 266 if (pm0->pm_num == up->up_msg_num) { 267 up->up_msg_num++; 268 } 269 pm2 = pm1; 270 } else if (t == 2) { 271 /* Check if we need to increment the message number. */ 272 if (pm1->pm_num == up->up_msg_num) { 273 up->up_msg_num++; 274 } 275 pm2 = pm0; 276 } else if (t == 3) { 277 /* 278 * Both entries are queued. Re-queue the entry closest to 279 * the end. 280 */ 281 d = (pm1->pm_num - pm0->pm_num); 282 283 /* Check sign after subtraction */ 284 if (d & 0x80000000) { 285 pm2 = pm0; 286 } else { 287 pm2 = pm1; 288 } 289 290 TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); 291 } else { 292 pm2 = NULL; /* panic - should not happen */ 293 } 294 295 DPRINTF(" t=%u, num=%u\n", t, up->up_msg_num); 296 297 /* Put message last on queue */ 298 299 pm2->pm_num = up->up_msg_num; 300 TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); 301 302 /* Check if we need to wakeup the USB process. */ 303 304 if (up->up_msleep) { 305 up->up_msleep = 0; /* save "cv_signal()" calls */ 306 usb2_cv_signal(&up->up_cv); 307 } 308 return (pm2); 309} 310 311/*------------------------------------------------------------------------* 312 * usb2_proc_is_gone 313 * 314 * Return values: 315 * 0: USB process is running 316 * Else: USB process is tearing down 317 *------------------------------------------------------------------------*/ 318uint8_t 319usb2_proc_is_gone(struct usb2_process *up) 320{ 321 mtx_assert(up->up_mtx, MA_OWNED); 322 323 return (up->up_gone ? 1 : 0); 324} 325 326/*------------------------------------------------------------------------* 327 * usb2_proc_mwait 328 * 329 * This function will return when the USB process message pointed to 330 * by "pm" is no longer on a queue. This function must be called 331 * having "up->up_mtx" locked. 332 *------------------------------------------------------------------------*/ 333void 334usb2_proc_mwait(struct usb2_process *up, void *_pm0, void *_pm1) 335{ 336 struct usb2_proc_msg *pm0 = _pm0; 337 struct usb2_proc_msg *pm1 = _pm1; 338 339 mtx_assert(up->up_mtx, MA_OWNED); 340 341 if (up->up_curtd == curthread) { 342 /* Just remove the messages from the queue. */ 343 if (pm0->pm_qentry.tqe_prev) { 344 TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); 345 pm0->pm_qentry.tqe_prev = NULL; 346 } 347 if (pm1->pm_qentry.tqe_prev) { 348 TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); 349 pm1->pm_qentry.tqe_prev = NULL; 350 } 351 } else 352 while (pm0->pm_qentry.tqe_prev || 353 pm1->pm_qentry.tqe_prev) { 354 /* check if config thread is gone */ 355 if (up->up_gone) 356 break; 357 up->up_dsleep = 1; 358 usb2_cv_wait(&up->up_drain, up->up_mtx); 359 } 360} 361 362/*------------------------------------------------------------------------* 363 * usb2_proc_drain 364 * 365 * This function will tear down an USB process, waiting for the 366 * currently executing command to return. 367 * 368 * NOTE: If the structure pointed to by "up" is all zero, 369 * this function does nothing. 370 *------------------------------------------------------------------------*/ 371void 372usb2_proc_drain(struct usb2_process *up) 373{ 374 if (!(up->up_mtx)) { 375 /* not initialised */ 376 return; 377 } 378 if (up->up_mtx != &Giant) { 379 mtx_assert(up->up_mtx, MA_NOTOWNED); 380 } 381 mtx_lock(up->up_mtx); 382 383 /* Set the gone flag */ 384 385 up->up_gone = 1; 386 387 while (up->up_ptr) { 388 389 /* Check if we need to wakeup the USB process */ 390 391 if (up->up_msleep || up->up_csleep) { 392 up->up_msleep = 0; 393 up->up_csleep = 0; 394 usb2_cv_signal(&up->up_cv); 395 } 396 /* Check if we are still cold booted */ 397 398 if (cold) { 399 USB_THREAD_SUSPEND(up->up_ptr); 400 printf("WARNING: A USB process has been left suspended!\n"); 401 break; 402 } 403 usb2_cv_wait(&up->up_cv, up->up_mtx); 404 } 405 /* Check if someone is waiting - should not happen */ 406 407 if (up->up_dsleep) { 408 up->up_dsleep = 0; 409 usb2_cv_broadcast(&up->up_drain); 410 DPRINTF("WARNING: Someone is waiting " 411 "for USB process drain!\n"); 412 } 413 mtx_unlock(up->up_mtx); 414} 415 416/*------------------------------------------------------------------------* 417 * usb2_proc_cwait 418 * 419 * This function will suspend the current process until 420 * "usb2_proc_signal()" or "usb2_proc_drain()" is called. The 421 * "timeout" parameter defines the maximum wait time in system 422 * ticks. If "timeout" is zero that means no timeout. 423 * 424 * NOTE: This function can only be called from within an USB process. 425 * 426 * Return values: 427 * USB_PROC_WAIT_TIMEOUT: Timeout 428 * USB_PROC_WAIT_NORMAL: Success 429 * Else: USB process is tearing down 430 *------------------------------------------------------------------------*/ 431uint8_t 432usb2_proc_cwait(struct usb2_process *up, int timeout) 433{ 434 int error; 435 436 mtx_assert(up->up_mtx, MA_OWNED); 437 438 if (up->up_gone) { 439 return (USB_PROC_WAIT_DRAIN); 440 } 441 up->up_csleep = 1; 442 443 if (timeout == 0) { 444 usb2_cv_wait(&up->up_cv, up->up_mtx); 445 error = 0; 446 } else { 447 error = usb2_cv_timedwait(&up->up_cv, up->up_mtx, timeout); 448 } 449 450 up->up_csleep = 0; 451 452 if (up->up_gone) { 453 return (USB_PROC_WAIT_DRAIN); 454 } 455 if (error == EWOULDBLOCK) { 456 return (USB_PROC_WAIT_TIMEOUT); 457 } 458 return (0); 459} 460 461/*------------------------------------------------------------------------* 462 * usb2_proc_csignal 463 * 464 * This function will wakeup the given USB process. 465 *------------------------------------------------------------------------*/ 466void 467usb2_proc_csignal(struct usb2_process *up) 468{ 469 mtx_assert(up->up_mtx, MA_OWNED); 470 471 if (up->up_csleep) { 472 up->up_csleep = 0; 473 usb2_cv_signal(&up->up_cv); 474 } 475} 476