Date: Tue, 27 Jan 2009 01:21:12 +0000 (UTC) From: Andrew Thompson <thompsa@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r187750 - in user/thompsa/usb/sys/dev/usb2: controller core Message-ID: <200901270121.n0R1LCS9069217@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: thompsa Date: Tue Jan 27 01:21:11 2009 New Revision: 187750 URL: http://svn.freebsd.org/changeset/base/187750 Log: Change over to using taskqueue(9) instead of hand rolled threads and the config_td system. Deleted: user/thompsa/usb/sys/dev/usb2/core/usb2_config_td.c user/thompsa/usb/sys/dev/usb2/core/usb2_config_td.h Modified: user/thompsa/usb/sys/dev/usb2/controller/usb2_bus.h user/thompsa/usb/sys/dev/usb2/controller/usb2_controller.c user/thompsa/usb/sys/dev/usb2/core/usb2_device.c user/thompsa/usb/sys/dev/usb2/core/usb2_device.h user/thompsa/usb/sys/dev/usb2/core/usb2_hub.c user/thompsa/usb/sys/dev/usb2/core/usb2_process.c user/thompsa/usb/sys/dev/usb2/core/usb2_process.h user/thompsa/usb/sys/dev/usb2/core/usb2_transfer.c user/thompsa/usb/sys/dev/usb2/core/usb2_transfer.h Modified: user/thompsa/usb/sys/dev/usb2/controller/usb2_bus.h ============================================================================== --- user/thompsa/usb/sys/dev/usb2/controller/usb2_bus.h Tue Jan 27 00:31:25 2009 (r187749) +++ user/thompsa/usb/sys/dev/usb2/controller/usb2_bus.h Tue Jan 27 01:21:11 2009 (r187750) @@ -28,16 +28,6 @@ #define _USB2_BUS_H_ /* - * The following structure defines the USB explore message sent to the - * USB explore process. - */ - -struct usb2_bus_msg { - struct usb2_proc_msg hdr; - struct usb2_bus *bus; -}; - -/* * The following structure defines the USB statistics structure. */ struct usb2_bus_stat { @@ -51,23 +41,14 @@ struct usb2_bus_stat { struct usb2_bus { struct usb2_bus_stat stats_err; struct usb2_bus_stat stats_ok; + struct usb2_process done_proc; struct usb2_process explore_proc; - struct usb2_process roothub_proc; - /* - * There are two callback processes. One for Giant locked - * callbacks. One for non-Giant locked callbacks. This should - * avoid congestion and reduce response time in most cases. - */ - struct usb2_process giant_callback_proc; - struct usb2_process non_giant_callback_proc; - struct usb2_bus_msg explore_msg[2]; - struct usb2_bus_msg detach_msg[2]; - struct usb2_bus_msg attach_msg[2]; - struct usb2_bus_msg roothub_msg[2]; - /* - * This mutex protects the USB hardware: - */ - struct mtx bus_mtx; + struct usb2_task explore_task; + struct usb2_task attach_task; + struct usb2_task detach_task; + struct usb2_task roothub_task; + struct mtx bus_mtx; /* This mutex protects the USB + * hardware */ struct usb2_perm perm; struct usb2_xfer_queue intr_q; struct usb2_callout power_wdog; /* power management */ Modified: user/thompsa/usb/sys/dev/usb2/controller/usb2_controller.c ============================================================================== --- user/thompsa/usb/sys/dev/usb2/controller/usb2_controller.c Tue Jan 27 00:31:25 2009 (r187749) +++ user/thompsa/usb/sys/dev/usb2/controller/usb2_controller.c Tue Jan 27 01:21:11 2009 (r187750) @@ -43,6 +43,10 @@ #include <dev/usb2/controller/usb2_bus.h> /* function prototypes */ +static usb2_task_fn_t usb2_bus_explore; +static usb2_task_fn_t usb2_bus_attach; +static usb2_task_fn_t usb2_bus_detach; +static usb2_task_fn_t usb2_bus_roothub; static device_probe_t usb2_probe; static device_attach_t usb2_attach; @@ -59,7 +63,6 @@ static void usb2_bus_mem_alloc_all_cb(st static void usb2_bus_mem_free_all_cb(struct usb2_bus *, struct usb2_page_cache *, struct usb2_page *, uint32_t, uint32_t); -static void usb2_bus_roothub(struct usb2_proc_msg *pm); /* static variables */ @@ -153,31 +156,13 @@ usb2_detach(device_t dev) usb2_callout_drain(&bus->power_wdog); /* Let the USB explore process detach all devices. */ - - USB_BUS_LOCK(bus); - if (usb2_proc_msignal(&bus->explore_proc, - &bus->detach_msg[0], &bus->detach_msg[1])) { - /* ignore */ - } + usb2_proc_enqueue(&bus->explore_proc, &bus->explore_task); /* Wait for detach to complete */ + usb2_proc_drain(&bus->explore_proc, &bus->explore_task); - usb2_proc_mwait(&bus->explore_proc, - &bus->detach_msg[0], &bus->detach_msg[1]); - - USB_BUS_UNLOCK(bus); - - /* Get rid of USB callback processes */ - - usb2_proc_unsetup(&bus->giant_callback_proc); - usb2_proc_unsetup(&bus->non_giant_callback_proc); - - /* Get rid of USB roothub process */ - - usb2_proc_unsetup(&bus->roothub_proc); - - /* Get rid of USB explore process */ - - usb2_proc_unsetup(&bus->explore_proc); + /* Get rid of USB processes */ + usb2_proc_free(&bus->done_proc); + usb2_proc_free(&bus->explore_proc); return (0); } @@ -188,14 +173,14 @@ usb2_detach(device_t dev) * This function is used to explore the device tree from the root. *------------------------------------------------------------------------*/ static void -usb2_bus_explore(struct usb2_proc_msg *pm) +usb2_bus_explore(void *context, struct usb2_task *task) { - struct usb2_bus *bus; + struct usb2_bus *bus = context; struct usb2_device *udev; - bus = ((struct usb2_bus_msg *)pm)->bus; udev = bus->devices[USB_ROOT_HUB_ADDR]; + USB_BUS_LOCK(bus); if (udev && udev->hub) { if (bus->do_probe) { @@ -208,8 +193,6 @@ usb2_bus_explore(struct usb2_proc_msg *p } USB_BUS_UNLOCK(bus); - mtx_lock(&Giant); - /* * First update the USB power state! */ @@ -219,12 +202,12 @@ usb2_bus_explore(struct usb2_proc_msg *p * Explore the Root USB HUB. This call can sleep, * exiting Giant, which is actually Giant. */ + mtx_lock(&Giant); (udev->hub->explore) (udev); - mtx_unlock(&Giant); - - USB_BUS_LOCK(bus); + return; } + USB_BUS_UNLOCK(bus); } /*------------------------------------------------------------------------* @@ -233,13 +216,13 @@ usb2_bus_explore(struct usb2_proc_msg *p * This function is used to detach the device tree from the root. *------------------------------------------------------------------------*/ static void -usb2_bus_detach(struct usb2_proc_msg *pm) +usb2_bus_detach(void *context, struct usb2_task *task) { - struct usb2_bus *bus; + struct usb2_bus *bus = context; struct usb2_device *udev; device_t dev; - bus = ((struct usb2_bus_msg *)pm)->bus; + USB_BUS_LOCK(bus); udev = bus->devices[USB_ROOT_HUB_ADDR]; dev = bus->bdev; /* clear the softc */ @@ -262,6 +245,7 @@ usb2_bus_detach(struct usb2_proc_msg *pm USB_BUS_LOCK(bus); /* clear bdev variable last */ bus->bdev = NULL; + USB_BUS_UNLOCK(bus); } static void @@ -287,15 +271,14 @@ usb2_power_wdog(void *arg) * This function attaches USB in context of the explore thread. *------------------------------------------------------------------------*/ static void -usb2_bus_attach(struct usb2_proc_msg *pm) +usb2_bus_attach(void *context, struct usb2_task *task) { - struct usb2_bus *bus; + struct usb2_bus *bus = context; struct usb2_device *child; device_t dev; usb2_error_t err; uint8_t speed; - bus = ((struct usb2_bus_msg *)pm)->bus; dev = bus->bdev; DPRINTF("\n"); @@ -326,11 +309,9 @@ usb2_bus_attach(struct usb2_proc_msg *pm return; } - USB_BUS_UNLOCK(bus); mtx_lock(&Giant); /* XXX not required by USB */ /* Allocate the Root USB device */ - child = usb2_alloc_device(bus->bdev, bus, NULL, 0, 0, 1, speed, USB_MODE_HOST); if (child) { @@ -344,9 +325,7 @@ usb2_bus_attach(struct usb2_proc_msg *pm } else { err = USB_ERR_NOMEM; } - mtx_unlock(&Giant); - USB_BUS_LOCK(bus); if (err) { device_printf(bus->bdev, "Root HUB problem, error=%s\n", @@ -357,10 +336,8 @@ usb2_bus_attach(struct usb2_proc_msg *pm device_set_softc(dev, bus); /* start watchdog - this function will unlock the BUS lock ! */ - usb2_power_wdog(bus); - - /* need to return locked */ USB_BUS_LOCK(bus); + usb2_power_wdog(bus); } /*------------------------------------------------------------------------* @@ -376,53 +353,20 @@ static void usb2_attach_sub(device_t dev, struct usb2_bus *bus) { /* Initialise USB process messages */ - bus->explore_msg[0].hdr.pm_callback = &usb2_bus_explore; - bus->explore_msg[0].bus = bus; - bus->explore_msg[1].hdr.pm_callback = &usb2_bus_explore; - bus->explore_msg[1].bus = bus; - - bus->detach_msg[0].hdr.pm_callback = &usb2_bus_detach; - bus->detach_msg[0].bus = bus; - bus->detach_msg[1].hdr.pm_callback = &usb2_bus_detach; - bus->detach_msg[1].bus = bus; - - bus->attach_msg[0].hdr.pm_callback = &usb2_bus_attach; - bus->attach_msg[0].bus = bus; - bus->attach_msg[1].hdr.pm_callback = &usb2_bus_attach; - bus->attach_msg[1].bus = bus; - - bus->roothub_msg[0].hdr.pm_callback = &usb2_bus_roothub; - bus->roothub_msg[0].bus = bus; - bus->roothub_msg[1].hdr.pm_callback = &usb2_bus_roothub; - bus->roothub_msg[1].bus = bus; - - /* Create USB explore, roothub and callback processes */ - - if (usb2_proc_setup(&bus->giant_callback_proc, - &bus->bus_mtx, USB_PRI_MED)) { - printf("WARNING: Creation of USB Giant " - "callback process failed.\n"); - } else if (usb2_proc_setup(&bus->non_giant_callback_proc, - &bus->bus_mtx, USB_PRI_HIGH)) { - printf("WARNING: Creation of USB non-Giant " - "callback process failed.\n"); - } else if (usb2_proc_setup(&bus->roothub_proc, - &bus->bus_mtx, USB_PRI_HIGH)) { - printf("WARNING: Creation of USB roothub " - "process failed.\n"); - } else if (usb2_proc_setup(&bus->explore_proc, - &bus->bus_mtx, USB_PRI_MED)) { - printf("WARNING: Creation of USB explore " - "process failed.\n"); - } else { - /* Get final attach going */ - USB_BUS_LOCK(bus); - if (usb2_proc_msignal(&bus->explore_proc, - &bus->attach_msg[0], &bus->attach_msg[1])) { - /* ignore */ - } - USB_BUS_UNLOCK(bus); - } + USB_TASK_INIT(&bus->explore_task, usb2_bus_explore, bus, NULL); + USB_TASK_INIT(&bus->attach_task, usb2_bus_attach, bus, NULL); + USB_TASK_INIT(&bus->detach_task, usb2_bus_detach, bus, NULL); + USB_TASK_INIT(&bus->roothub_task, usb2_bus_roothub, bus, NULL); + + /* Create a new USB process */ + usb2_proc_create(&bus->explore_proc, USB_PRI_MED, + device_get_nameunit(dev)); + usb2_proc_create(&bus->done_proc, USB_PRI_HIGH, + device_get_nameunit(bus->parent)); + + /* Get final attach going */ + usb2_proc_enqueue(&bus->explore_proc, &bus->attach_task); + } /*------------------------------------------------------------------------* @@ -580,15 +524,13 @@ usb2_bus_mem_free_all(struct usb2_bus *b * roothub and is called from the roothub process. *------------------------------------------------------------------------*/ static void -usb2_bus_roothub(struct usb2_proc_msg *pm) +usb2_bus_roothub(void *context, struct usb2_task *task) { - struct usb2_bus *bus; - - bus = ((struct usb2_bus_msg *)pm)->bus; - - USB_BUS_LOCK_ASSERT(bus, MA_OWNED); + struct usb2_bus *bus = context; + USB_BUS_LOCK(bus); (bus->methods->roothub_exec) (bus); + USB_BUS_UNLOCK(bus); } /*------------------------------------------------------------------------* @@ -602,8 +544,5 @@ usb2_bus_roothub_exec(struct usb2_bus *b { USB_BUS_LOCK_ASSERT(bus, MA_OWNED); - if (usb2_proc_msignal(&bus->roothub_proc, - &bus->roothub_msg[0], &bus->roothub_msg[1])) { - /* ignore */ - } + usb2_proc_enqueue(&bus->done_proc, &bus->roothub_task); } Modified: user/thompsa/usb/sys/dev/usb2/core/usb2_device.c ============================================================================== --- user/thompsa/usb/sys/dev/usb2/core/usb2_device.c Tue Jan 27 00:31:25 2009 (r187749) +++ user/thompsa/usb/sys/dev/usb2/core/usb2_device.c Tue Jan 27 01:21:11 2009 (r187750) @@ -55,6 +55,7 @@ #include <dev/usb2/controller/usb2_bus.h> /* function prototypes */ +static usb2_task_fn_t usb2_clear_stall; static void usb2_fill_pipe_data(struct usb2_device *, uint8_t, struct usb2_endpoint_descriptor *, struct usb2_pipe *); @@ -68,7 +69,6 @@ static void usb2_init_attach_arg(struct struct usb2_attach_arg *); static void usb2_suspend_resume_sub(struct usb2_device *, device_t, uint8_t); -static void usb2_clear_stall_proc(struct usb2_proc_msg *_pm); static void usb2_check_strings(struct usb2_device *); static usb2_error_t usb2_fill_iface_data(struct usb2_device *, uint8_t, uint8_t); @@ -1221,26 +1221,19 @@ usb2_suspend_resume(struct usb2_device * } /*------------------------------------------------------------------------* - * usb2_clear_stall_proc + * usb2_clear_stall * * This function performs generic USB clear stall operations. *------------------------------------------------------------------------*/ static void -usb2_clear_stall_proc(struct usb2_proc_msg *_pm) +usb2_clear_stall(void *context, struct usb2_task *task) { - struct usb2_clear_stall_msg *pm = (void *)_pm; - struct usb2_device *udev = pm->udev; - - /* Change lock */ - USB_BUS_UNLOCK(udev->bus); - mtx_lock(udev->default_mtx); + struct usb2_device *udev = context; /* Start clear stall callback */ + mtx_lock(udev->default_mtx); usb2_transfer_start(udev->default_xfer[1]); - - /* Change lock */ mtx_unlock(udev->default_mtx); - USB_BUS_LOCK(udev->bus); } /*------------------------------------------------------------------------* @@ -1314,10 +1307,7 @@ usb2_alloc_device(device_t parent_dev, s mtx_init(udev->default_mtx, "USB device mutex", NULL, MTX_DEF); /* initialise generic clear stall */ - udev->cs_msg[0].hdr.pm_callback = &usb2_clear_stall_proc; - udev->cs_msg[0].udev = udev; - udev->cs_msg[1].hdr.pm_callback = &usb2_clear_stall_proc; - udev->cs_msg[1].udev = udev; + USB_TASK_INIT(&udev->clearstall_task, usb2_clear_stall, udev, NULL); /* initialise some USB device fields */ udev->parent_hub = parent_hub; @@ -1722,14 +1712,11 @@ usb2_free_device(struct usb2_device *ude /* template unsetup, if any */ (usb2_temp_unsetup_p) (udev); - /* + /* * Make sure that our clear-stall messages are not queued * anywhere: */ - USB_BUS_LOCK(udev->bus); - usb2_proc_mwait(&udev->bus->non_giant_callback_proc, - &udev->cs_msg[0], &udev->cs_msg[1]); - USB_BUS_UNLOCK(udev->bus); + usb2_proc_drain(&bus->done_proc, &udev->clearstall_task); sx_destroy(udev->default_sx); sx_destroy(udev->default_sx + 1); Modified: user/thompsa/usb/sys/dev/usb2/core/usb2_device.h ============================================================================== --- user/thompsa/usb/sys/dev/usb2/core/usb2_device.h Tue Jan 27 00:31:25 2009 (r187749) +++ user/thompsa/usb/sys/dev/usb2/core/usb2_device.h Tue Jan 27 01:21:11 2009 (r187750) @@ -31,11 +31,6 @@ struct usb2_symlink; #define USB_DEFAULT_XFER_MAX 2 -struct usb2_clear_stall_msg { - struct usb2_proc_msg hdr; - struct usb2_device *udev; -}; - /* * The following structure defines an USB pipe which is equal to an * USB endpoint. @@ -99,8 +94,8 @@ struct usb2_power_save { * these structures for every USB device. */ struct usb2_device { - struct usb2_clear_stall_msg cs_msg[2]; /* generic clear stall - * messages */ + struct usb2_task clearstall_task; + struct usb2_perm perm; struct sx default_sx[2]; struct mtx default_mtx[1]; Modified: user/thompsa/usb/sys/dev/usb2/core/usb2_hub.c ============================================================================== --- user/thompsa/usb/sys/dev/usb2/core/usb2_hub.c Tue Jan 27 00:31:25 2009 (r187749) +++ user/thompsa/usb/sys/dev/usb2/core/usb2_hub.c Tue Jan 27 01:21:11 2009 (r187750) @@ -1354,10 +1354,7 @@ usb2_needs_explore(struct usb2_bus *bus, if (do_probe) { bus->do_probe = 1; } - if (usb2_proc_msignal(&bus->explore_proc, - &bus->explore_msg[0], &bus->explore_msg[1])) { - /* ignore */ - } + usb2_proc_enqueue(&bus->explore_proc, &bus->explore_task); USB_BUS_UNLOCK(bus); } Modified: user/thompsa/usb/sys/dev/usb2/core/usb2_process.c ============================================================================== --- user/thompsa/usb/sys/dev/usb2/core/usb2_process.c Tue Jan 27 00:31:25 2009 (r187749) +++ user/thompsa/usb/sys/dev/usb2/core/usb2_process.c Tue Jan 27 01:21:11 2009 (r187750) @@ -31,26 +31,8 @@ #include <dev/usb2/core/usb2_debug.h> #include <dev/usb2/core/usb2_util.h> -#include <sys/proc.h> -#include <sys/kthread.h> -#include <sys/sched.h> - -#if (__FreeBSD_version < 700000) -#define thread_lock(td) mtx_lock_spin(&sched_lock) -#define thread_unlock(td) mtx_unlock_spin(&sched_lock) -#endif +#include <sys/taskqueue.h> -#if (__FreeBSD_version >= 800000) -#define USB_THREAD_CREATE(f, s, p, ...) \ - kproc_create((f), (s), (p), RFHIGHPID, 0, __VA_ARGS__) -#define USB_THREAD_SUSPEND(p) kproc_suspend(p,0) -#define USB_THREAD_EXIT(err) kproc_exit(err) -#else -#define USB_THREAD_CREATE(f, s, p, ...) \ - kthread_create((f), (s), (p), RFHIGHPID, 0, __VA_ARGS__) -#define USB_THREAD_SUSPEND(p) kthread_suspend(p,0) -#define USB_THREAD_EXIT(err) kthread_exit(err) -#endif #if USB_DEBUG static int usb2_proc_debug; @@ -60,416 +42,67 @@ SYSCTL_INT(_hw_usb2_proc, OID_AUTO, debu "Debug level"); #endif -/*------------------------------------------------------------------------* - * usb2_process - * - * This function is the USB process dispatcher. - *------------------------------------------------------------------------*/ -static void -usb2_process(void *arg) -{ - struct usb2_process *up = arg; - struct usb2_proc_msg *pm; - struct thread *td; - - /* adjust priority */ - td = curthread; - thread_lock(td); - sched_prio(td, up->up_prio); - thread_unlock(td); - - mtx_lock(up->up_mtx); - - up->up_curtd = td; - - while (1) { - - if (up->up_gone) { - break; - } - /* - * NOTE to reimplementors: dequeueing a command from the - * "used" queue and executing it must be atomic, with regard - * to the "up_mtx" mutex. That means any attempt to queue a - * command by another thread must be blocked until either: - * - * 1) the command sleeps - * - * 2) the command returns - * - * Here is a practical example that shows how this helps - * solving a problem: - * - * Assume that you want to set the baud rate on a USB serial - * device. During the programming of the device you don't - * want to receive nor transmit any data, because it will be - * garbage most likely anyway. The programming of our USB - * device takes 20 milliseconds and it needs to call - * functions that sleep. - * - * Non-working solution: Before we queue the programming - * command, we stop transmission and reception of data. Then - * we queue a programming command. At the end of the - * programming command we enable transmission and reception - * of data. - * - * Problem: If a second programming command is queued while the - * first one is sleeping, we end up enabling transmission - * and reception of data too early. - * - * Working solution: Before we queue the programming command, - * we stop transmission and reception of data. Then we queue - * a programming command. Then we queue a second command - * that only enables transmission and reception of data. - * - * Why it works: If a second programming command is queued - * while the first one is sleeping, then the queueing of a - * second command to enable the data transfers, will cause - * the previous one, which is still on the queue, to be - * removed from the queue, and re-inserted after the last - * baud rate programming command, which then gives the - * desired result. - */ - pm = TAILQ_FIRST(&up->up_qhead); - - if (pm) { - DPRINTF("Message pm=%p, cb=%p (enter)\n", - pm, pm->pm_callback); - - (pm->pm_callback) (pm); - - if (pm == TAILQ_FIRST(&up->up_qhead)) { - /* nothing changed */ - TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); - pm->pm_qentry.tqe_prev = NULL; - } - DPRINTF("Message pm=%p (leave)\n", pm); - - continue; - } - /* end if messages - check if anyone is waiting for sync */ - if (up->up_dsleep) { - up->up_dsleep = 0; - usb2_cv_broadcast(&up->up_drain); - } - up->up_msleep = 1; - usb2_cv_wait(&up->up_cv, up->up_mtx); - } - - up->up_ptr = NULL; - usb2_cv_signal(&up->up_cv); - mtx_unlock(up->up_mtx); - - USB_THREAD_EXIT(0); -} - -/*------------------------------------------------------------------------* - * usb2_proc_setup - * - * This function will create a process using the given "prio" that can - * execute callbacks. The mutex pointed to by "p_mtx" will be applied - * before calling the callbacks and released after that the callback - * has returned. The structure pointed to by "up" is assumed to be - * zeroed before this function is called. - * - * Return values: - * 0: success - * Else: failure - *------------------------------------------------------------------------*/ -uint8_t -usb2_proc_setup(struct usb2_process *up, struct mtx *p_mtx, uint8_t prio) +int +usb2_proc_create(struct usb2_process *up, int prio, const char *name) { - up->up_mtx = p_mtx; - up->up_prio = prio; - - TAILQ_INIT(&up->up_qhead); - - usb2_cv_init(&up->up_cv, "WMSG"); - usb2_cv_init(&up->up_drain, "DMSG"); - - if (USB_THREAD_CREATE(&usb2_process, up, - &up->up_ptr, "USBPROC")) { - DPRINTFN(0, "Unable to create USB process."); - up->up_ptr = NULL; - goto error; - } + up->up_tq = taskqueue_create(name, M_WAITOK, + taskqueue_thread_enqueue, &up->up_tq); + if (up->up_tq == NULL) + return (ENOMEM); + taskqueue_start_threads(&up->up_tq, 1, prio, + "usb: %s", name); return (0); - -error: - usb2_proc_unsetup(up); - return (1); } -/*------------------------------------------------------------------------* - * usb2_proc_unsetup - * - * NOTE: If the structure pointed to by "up" is all zero, this - * function does nothing. - * - * NOTE: Messages that are pending on the process queue will not be - * removed nor called. - *------------------------------------------------------------------------*/ void -usb2_proc_unsetup(struct usb2_process *up) +usb2_proc_free(struct usb2_process *up) { - if (!(up->up_mtx)) { - /* not initialised */ - return; - } - usb2_proc_drain(up); - - usb2_cv_destroy(&up->up_cv); - usb2_cv_destroy(&up->up_drain); - - /* make sure that we do not enter here again */ - up->up_mtx = NULL; -} - -/*------------------------------------------------------------------------* - * usb2_proc_msignal - * - * This function will queue one of the passed USB process messages on - * the USB process queue. The first message that is not already queued - * will get queued. If both messages are already queued the one queued - * last will be removed from the queue and queued in the end. The USB - * process mutex must be locked when calling this function. This - * function exploits the fact that a process can only do one callback - * at a time. The message that was queued is returned. - *------------------------------------------------------------------------*/ -void * -usb2_proc_msignal(struct usb2_process *up, void *_pm0, void *_pm1) -{ - struct usb2_proc_msg *pm0 = _pm0; - struct usb2_proc_msg *pm1 = _pm1; - struct usb2_proc_msg *pm2; - uint32_t d; - uint8_t t; - - mtx_assert(up->up_mtx, MA_OWNED); - - t = 0; - - if (pm0->pm_qentry.tqe_prev) { - t |= 1; - } - if (pm1->pm_qentry.tqe_prev) { - t |= 2; - } - if (t == 0) { - /* - * No entries are queued. Queue "pm0" and use the existing - * message number. - */ - pm2 = pm0; - } else if (t == 1) { - /* Check if we need to increment the message number. */ - if (pm0->pm_num == up->up_msg_num) { - up->up_msg_num++; - } - pm2 = pm1; - } else if (t == 2) { - /* Check if we need to increment the message number. */ - if (pm1->pm_num == up->up_msg_num) { - up->up_msg_num++; - } - pm2 = pm0; - } else if (t == 3) { - /* - * Both entries are queued. Re-queue the entry closest to - * the end. - */ - d = (pm1->pm_num - pm0->pm_num); - - /* Check sign after subtraction */ - if (d & 0x80000000) { - pm2 = pm0; - } else { - pm2 = pm1; - } - - TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); - } else { - pm2 = NULL; /* panic - should not happen */ - } - - DPRINTF(" t=%u, num=%u\n", t, up->up_msg_num); - - /* Put message last on queue */ - - pm2->pm_num = up->up_msg_num; - TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); - - /* Check if we need to wakeup the USB process. */ - - if (up->up_msleep) { - up->up_msleep = 0; /* save "cv_signal()" calls */ - usb2_cv_signal(&up->up_cv); + if (up->up_tq) { + taskqueue_free(up->up_tq); + up->up_tq = NULL; } - return (pm2); } -/*------------------------------------------------------------------------* - * usb2_proc_is_gone - * - * Return values: - * 0: USB process is running - * Else: USB process is tearing down - *------------------------------------------------------------------------*/ -uint8_t -usb2_proc_is_gone(struct usb2_process *up) +void +usb2_proc_block(struct usb2_process *up) { - mtx_assert(up->up_mtx, MA_OWNED); - - return (up->up_gone ? 1 : 0); + taskqueue_block(up->up_tq); } -/*------------------------------------------------------------------------* - * usb2_proc_mwait - * - * This function will return when the USB process message pointed to - * by "pm" is no longer on a queue. This function must be called - * having "up->up_mtx" locked. - *------------------------------------------------------------------------*/ void -usb2_proc_mwait(struct usb2_process *up, void *_pm0, void *_pm1) +usb2_proc_unblock(struct usb2_process *up) { - struct usb2_proc_msg *pm0 = _pm0; - struct usb2_proc_msg *pm1 = _pm1; - - mtx_assert(up->up_mtx, MA_OWNED); - - if (up->up_curtd == curthread) { - /* Just remove the messages from the queue. */ - if (pm0->pm_qentry.tqe_prev) { - TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); - pm0->pm_qentry.tqe_prev = NULL; - } - if (pm1->pm_qentry.tqe_prev) { - TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); - pm1->pm_qentry.tqe_prev = NULL; - } - } else - while (pm0->pm_qentry.tqe_prev || - pm1->pm_qentry.tqe_prev) { - /* check if config thread is gone */ - if (up->up_gone) - break; - up->up_dsleep = 1; - usb2_cv_wait(&up->up_drain, up->up_mtx); - } + taskqueue_unblock(up->up_tq); } -/*------------------------------------------------------------------------* - * usb2_proc_drain - * - * This function will tear down an USB process, waiting for the - * currently executing command to return. - * - * NOTE: If the structure pointed to by "up" is all zero, - * this function does nothing. - *------------------------------------------------------------------------*/ void -usb2_proc_drain(struct usb2_process *up) +usb2_proc_enqueue(struct usb2_process *up, struct usb2_task *task) { - if (!(up->up_mtx)) { - /* not initialised */ + if (up->up_tq == NULL) return; - } - if (up->up_mtx != &Giant) { - mtx_assert(up->up_mtx, MA_NOTOWNED); - } - mtx_lock(up->up_mtx); - - /* Set the gone flag */ - - up->up_gone = 1; - - while (up->up_ptr) { - - /* Check if we need to wakeup the USB process */ - if (up->up_msleep || up->up_csleep) { - up->up_msleep = 0; - up->up_csleep = 0; - usb2_cv_signal(&up->up_cv); - } - /* Check if we are still cold booted */ - - if (cold) { - USB_THREAD_SUSPEND(up->up_ptr); - printf("WARNING: A USB process has been left suspended!\n"); - break; - } - usb2_cv_wait(&up->up_cv, up->up_mtx); - } - /* Check if someone is waiting - should not happen */ - - if (up->up_dsleep) { - up->up_dsleep = 0; - usb2_cv_broadcast(&up->up_drain); - DPRINTF("WARNING: Someone is waiting " - "for USB process drain!\n"); - } - mtx_unlock(up->up_mtx); + taskqueue_enqueue(up->up_tq, &task->ut_task); } -/*------------------------------------------------------------------------* - * usb2_proc_cwait - * - * This function will suspend the current process until - * "usb2_proc_signal()" or "usb2_proc_drain()" is called. The - * "timeout" parameter defines the maximum wait time in system - * ticks. If "timeout" is zero that means no timeout. - * - * NOTE: This function can only be called from within an USB process. - * - * Return values: - * USB_PROC_WAIT_TIMEOUT: Timeout - * USB_PROC_WAIT_NORMAL: Success - * Else: USB process is tearing down - *------------------------------------------------------------------------*/ -uint8_t -usb2_proc_cwait(struct usb2_process *up, int timeout) +void +usb2_proc_drain(struct usb2_process *up, struct usb2_task *task) { - int error; - - mtx_assert(up->up_mtx, MA_OWNED); - - if (up->up_gone) { - return (USB_PROC_WAIT_DRAIN); - } - up->up_csleep = 1; - - if (timeout == 0) { - usb2_cv_wait(&up->up_cv, up->up_mtx); - error = 0; - } else { - error = usb2_cv_timedwait(&up->up_cv, up->up_mtx, timeout); - } - - up->up_csleep = 0; - - if (up->up_gone) { - return (USB_PROC_WAIT_DRAIN); - } - if (error == EWOULDBLOCK) { - return (USB_PROC_WAIT_TIMEOUT); - } - return (0); + taskqueue_drain(up->up_tq, &task->ut_task); } /*------------------------------------------------------------------------* - * usb2_proc_csignal + * usb2_proc_dispatch * - * This function will wakeup the given USB process. + * This function is used to lock the mutex before calling the task *------------------------------------------------------------------------*/ void -usb2_proc_csignal(struct usb2_process *up) +usb2_proc_dispatch(void *arg, int pending) { - mtx_assert(up->up_mtx, MA_OWNED); + struct usb2_task *task = arg; - if (up->up_csleep) { - up->up_csleep = 0; - usb2_cv_signal(&up->up_cv); - } + if (task->ut_mtx) + mtx_lock(task->ut_mtx); + task->ut_func(task->ut_context, task); + if (task->ut_mtx) + mtx_unlock(task->ut_mtx); } Modified: user/thompsa/usb/sys/dev/usb2/core/usb2_process.h ============================================================================== --- user/thompsa/usb/sys/dev/usb2/core/usb2_process.h Tue Jan 27 00:31:25 2009 (r187749) +++ user/thompsa/usb/sys/dev/usb2/core/usb2_process.h Tue Jan 27 01:21:11 2009 (r187750) @@ -28,63 +28,47 @@ #define _USB2_PROCESS_H_ #include <sys/priority.h> +#include <sys/taskqueue.h> /* defines */ #define USB_PRI_HIGH PI_NET #define USB_PRI_MED PI_DISK +struct usb2_task; -#define USB_PROC_WAIT_TIMEOUT 2 -#define USB_PROC_WAIT_DRAIN 1 -#define USB_PROC_WAIT_NORMAL 0 - -/* structure prototypes */ - -struct usb2_proc_msg; - -/* typedefs */ - -typedef void (usb2_proc_callback_t)(struct usb2_proc_msg *hdr); - -/* - * The following structure defines the USB process message header. - */ -struct usb2_proc_msg { - TAILQ_ENTRY(usb2_proc_msg) pm_qentry; - usb2_proc_callback_t *pm_callback; - uint32_t pm_num; -}; - +typedef void usb2_task_fn_t(void *context, struct usb2_task *task); /* * The following structure defines the USB process. */ struct usb2_process { - TAILQ_HEAD(, usb2_proc_msg) up_qhead; - struct cv up_cv; - struct cv up_drain; - - struct proc *up_ptr; - struct thread *up_curtd; - struct mtx *up_mtx; - - uint32_t up_msg_num; - - uint8_t up_prio; - uint8_t up_gone; - uint8_t up_msleep; - uint8_t up_csleep; - uint8_t up_dsleep; + struct taskqueue *up_tq; }; -/* prototypes */ +struct usb2_task { + struct task ut_task; + struct mtx *ut_mtx; + usb2_task_fn_t *ut_func; + void *ut_context; + int ut_arg; +}; -uint8_t usb2_proc_cwait(struct usb2_process *up, int timeout); -uint8_t usb2_proc_is_gone(struct usb2_process *up); -uint8_t usb2_proc_setup(struct usb2_process *up, struct mtx *p_mtx, - uint8_t prio); -void usb2_proc_csignal(struct usb2_process *up); -void usb2_proc_drain(struct usb2_process *up); -void usb2_proc_mwait(struct usb2_process *up, void *pm0, void *pm1); -void usb2_proc_unsetup(struct usb2_process *up); -void *usb2_proc_msignal(struct usb2_process *up, void *pm0, void *pm1); +#define USB_TASK_INIT(t, f, c, m) do { \ + TASK_INIT(&(t)->ut_task, 0, usb2_proc_dispatch, t); \ + (t)->ut_func = (f); \ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901270121.n0R1LCS9069217>