when a usb transfer (xfer) is started, the underlying hci driver adds a timeout that adds a usb task that aborts the xfer.
if an xfer is synchronous, the upper usb layer sleeps waiting for the xfer to complete. it will also be woken up by the above mentioned abort task if the xfer times out. but what happens if a synchronous xfer run in the task thread stalls? it can't be aborted by the abort task, because that won't run until after the xfer wakes up! I'm pretty sure this is what's causing the boot hangs in PR 6491 and the one reported on m...@. afaics, this issue is not new, but now that we're using the task thread for attach/detach, we're more likely to hit it. the patch below solves the issue by running another task thread that is to be used ONLY for abort tasks. I first looked at making the upper usb layer timeout on it's own, but that's not possible without major redesign. I also thought about making the abort tasks workq tasks, but that doesn't work because there is more than one way to abort an xfer, and we may need to abort the abort task. workqs have no way to remove tasks from the queue but this is possible with usb tasks. it's not terribly easy to trigger an xfer timeout, but I did get at least two, and things did recover. unless someone sees a problem, or has a better solution, I think this should go in soon. yes, I had to hit each driver that uses usb tasks, but I think it's also better to be explicit, now that we have 3 different types of usb tasks ... -- [email protected] SDF Public Access UNIX System - http://sdf.lonestar.org Index: ehci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/ehci.c,v retrieving revision 1.112 diff -u -p ehci.c --- ehci.c 29 Sep 2010 20:06:38 -0000 1.112 +++ ehci.c 17 Oct 2010 22:12:50 -0000 @@ -1221,7 +1221,7 @@ ehci_allocx(struct usbd_bus *bus) if (xfer != NULL) { memset(xfer, 0, sizeof(struct ehci_xfer)); usb_init_task(&EXFER(xfer)->abort_task, ehci_timeout_task, - xfer); + xfer, USB_TASK_TYPE_ABORT); EXFER(xfer)->ehci_xfer_flags = 0; #ifdef DIAGNOSTIC EXFER(xfer)->isdone = 1; Index: if_atu.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_atu.c,v retrieving revision 1.94 diff -u -p if_atu.c --- if_atu.c 21 Nov 2009 14:18:34 -0000 1.94 +++ if_atu.c 17 Oct 2010 22:12:51 -0000 @@ -1467,7 +1467,7 @@ atu_complete_attach(struct atu_softc *sc) /* setup ifmedia interface */ ieee80211_media_init(ifp, atu_media_change, atu_media_status); - usb_init_task(&sc->sc_task, atu_task, sc); + usb_init_task(&sc->sc_task, atu_task, sc, USB_TASK_TYPE_GENERIC); #if NBPFILTER > 0 bpfattach(&sc->sc_radiobpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO, Index: if_aue.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_aue.c,v retrieving revision 1.79 diff -u -p if_aue.c --- if_aue.c 24 Sep 2010 08:33:58 -0000 1.79 +++ if_aue.c 17 Oct 2010 22:12:51 -0000 @@ -734,8 +734,10 @@ aue_attach(struct device *parent, struct device *self, return; } - usb_init_task(&sc->aue_tick_task, aue_tick_task, sc); - usb_init_task(&sc->aue_stop_task, (void (*)(void *))aue_stop, sc); + usb_init_task(&sc->aue_tick_task, aue_tick_task, sc, + USB_TASK_TYPE_GENERIC); + usb_init_task(&sc->aue_stop_task, (void (*)(void *))aue_stop, sc, + USB_TASK_TYPE_GENERIC); rw_init(&sc->aue_mii_lock, "auemii"); err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &iface); Index: if_axe.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_axe.c,v retrieving revision 1.99 diff -u -p if_axe.c --- if_axe.c 24 Sep 2010 03:21:21 -0000 1.99 +++ if_axe.c 17 Oct 2010 22:12:51 -0000 @@ -676,9 +676,11 @@ axe_attach(struct device *parent, struct device *self, sc->axe_flags = axe_lookup(uaa->vendor, uaa->product)->axe_flags; - usb_init_task(&sc->axe_tick_task, axe_tick_task, sc); + usb_init_task(&sc->axe_tick_task, axe_tick_task, sc, + USB_TASK_TYPE_GENERIC); rw_init(&sc->axe_mii_lock, "axemii"); - usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc); + usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc, + USB_TASK_TYPE_GENERIC); err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &sc->axe_iface); if (err) { Index: if_cue.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_cue.c,v retrieving revision 1.53 diff -u -p if_cue.c --- if_cue.c 24 Sep 2010 08:33:58 -0000 1.53 +++ if_cue.c 17 Oct 2010 22:12:51 -0000 @@ -470,8 +470,10 @@ cue_attach(struct device *parent, struct device *self, sc->cue_product = uaa->product; sc->cue_vendor = uaa->vendor; - usb_init_task(&sc->cue_tick_task, cue_tick_task, sc); - usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc); + usb_init_task(&sc->cue_tick_task, cue_tick_task, sc, + USB_TASK_TYPE_GENERIC); + usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc, + USB_TASK_TYPE_GENERIC); err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface); if (err) { Index: if_mos.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_mos.c,v retrieving revision 1.8 diff -u -p if_mos.c --- if_mos.c 24 Sep 2010 08:33:58 -0000 1.8 +++ if_mos.c 17 Oct 2010 22:12:51 -0000 @@ -652,9 +652,11 @@ mos_attach(struct device *parent, struct device *self, return; } - usb_init_task(&sc->mos_tick_task, mos_tick_task, sc); + usb_init_task(&sc->mos_tick_task, mos_tick_task, sc, + USB_TASK_TYPE_GENERIC); rw_init(&sc->mos_mii_lock, "mosmii"); - usb_init_task(&sc->mos_stop_task, (void (*)(void *))mos_stop, sc); + usb_init_task(&sc->mos_stop_task, (void (*)(void *))mos_stop, sc, + USB_TASK_TYPE_GENERIC); err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &sc->mos_iface); if (err) { Index: if_otus.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_otus.c,v retrieving revision 1.18 diff -u -p if_otus.c --- if_otus.c 27 Aug 2010 17:08:00 -0000 1.18 +++ if_otus.c 17 Oct 2010 22:12:51 -0000 @@ -203,7 +203,7 @@ otus_attach(struct device *parent, struct device *self sc->sc_udev = uaa->device; - usb_init_task(&sc->sc_task, otus_task, sc); + usb_init_task(&sc->sc_task, otus_task, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->scan_to, otus_next_scan, sc); timeout_set(&sc->calib_to, otus_calibrate_to, sc); Index: if_ral.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_ral.c,v retrieving revision 1.113 diff -u -p if_ral.c --- if_ral.c 27 Aug 2010 17:08:01 -0000 1.113 +++ if_ral.c 17 Oct 2010 22:12:51 -0000 @@ -273,7 +273,7 @@ ural_attach(struct device *parent, struct device *self return; } - usb_init_task(&sc->sc_task, ural_task, sc); + usb_init_task(&sc->sc_task, ural_task, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->scan_to, ural_next_scan, sc); sc->amrr.amrr_min_success_threshold = 1; Index: if_rum.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_rum.c,v retrieving revision 1.90 diff -u -p if_rum.c --- if_rum.c 27 Aug 2010 17:08:01 -0000 1.90 +++ if_rum.c 17 Oct 2010 22:12:52 -0000 @@ -328,7 +328,7 @@ rum_attach(struct device *parent, struct device *self, return; } - usb_init_task(&sc->sc_task, rum_task, sc); + usb_init_task(&sc->sc_task, rum_task, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->scan_to, rum_next_scan, sc); sc->amrr.amrr_min_success_threshold = 1; Index: if_run.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_run.c,v retrieving revision 1.71 diff -u -p if_run.c --- if_run.c 27 Aug 2010 17:08:01 -0000 1.71 +++ if_run.c 17 Oct 2010 22:12:52 -0000 @@ -471,7 +471,7 @@ run_attach(struct device *parent, struct device *self, return; } - usb_init_task(&sc->sc_task, run_task, sc); + usb_init_task(&sc->sc_task, run_task, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->scan_to, run_next_scan, sc); timeout_set(&sc->calib_to, run_calibrate_to, sc); Index: if_uath.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_uath.c,v retrieving revision 1.43 diff -u -p if_uath.c --- if_uath.c 27 Aug 2010 17:08:01 -0000 1.43 +++ if_uath.c 17 Oct 2010 22:12:52 -0000 @@ -298,7 +298,7 @@ uath_attach(struct device *parent, struct device *self /* * Only post-firmware devices here. */ - usb_init_task(&sc->sc_task, uath_task, sc); + usb_init_task(&sc->sc_task, uath_task, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->scan_to, uath_next_scan, sc); timeout_set(&sc->stat_to, uath_stat, sc); Index: if_udav.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_udav.c,v retrieving revision 1.46 diff -u -p if_udav.c --- if_udav.c 27 Aug 2010 07:08:22 -0000 1.46 +++ if_udav.c 17 Oct 2010 22:12:52 -0000 @@ -211,9 +211,11 @@ udav_attach(struct device *parent, struct device *self goto bad; } - usb_init_task(&sc->sc_tick_task, udav_tick_task, sc); + usb_init_task(&sc->sc_tick_task, udav_tick_task, sc, + USB_TASK_TYPE_GENERIC); rw_init(&sc->sc_mii_lock, "udavmii"); - usb_init_task(&sc->sc_stop_task, (void (*)(void *)) udav_stop_task, sc); + usb_init_task(&sc->sc_stop_task, (void (*)(void *)) udav_stop_task, sc, + USB_TASK_TYPE_GENERIC); /* get control interface */ err = usbd_device2interface_handle(dev, UDAV_IFACE_INDEX, &iface); Index: if_upgt.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_upgt.c,v retrieving revision 1.50 diff -u -p if_upgt.c --- if_upgt.c 27 Aug 2010 17:08:01 -0000 1.50 +++ if_upgt.c 17 Oct 2010 22:12:52 -0000 @@ -273,8 +273,9 @@ upgt_attach(struct device *parent, struct device *self } /* setup tasks and timeouts */ - usb_init_task(&sc->sc_task_newstate, upgt_newstate_task, sc); - usb_init_task(&sc->sc_task_tx, upgt_tx_task, sc); + usb_init_task(&sc->sc_task_newstate, upgt_newstate_task, sc, + USB_TASK_TYPE_GENERIC); + usb_init_task(&sc->sc_task_tx, upgt_tx_task, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->scan_to, upgt_next_scan, sc); timeout_set(&sc->led_to, upgt_set_led_blink, sc); Index: if_url.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_url.c,v retrieving revision 1.56 diff -u -p if_url.c --- if_url.c 27 Aug 2010 07:08:22 -0000 1.56 +++ if_url.c 17 Oct 2010 22:12:52 -0000 @@ -208,9 +208,11 @@ url_attach(struct device *parent, struct device *self, goto bad; } - usb_init_task(&sc->sc_tick_task, url_tick_task, sc); + usb_init_task(&sc->sc_tick_task, url_tick_task, sc, + USB_TASK_TYPE_GENERIC); rw_init(&sc->sc_mii_lock, "urlmii"); - usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc); + usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc, + USB_TASK_TYPE_GENERIC); /* get control interface */ err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface); Index: if_urtw.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_urtw.c,v retrieving revision 1.31 diff -u -p if_urtw.c --- if_urtw.c 27 Aug 2010 17:08:01 -0000 1.31 +++ if_urtw.c 17 Oct 2010 22:12:53 -0000 @@ -690,8 +690,9 @@ urtw_attach(struct device *parent, struct device *self /* XXX for what? */ sc->sc_preamble_mode = 2; - usb_init_task(&sc->sc_task, urtw_task, sc); - usb_init_task(&sc->sc_ledtask, urtw_ledusbtask, sc); + usb_init_task(&sc->sc_task, urtw_task, sc, USB_TASK_TYPE_GENERIC); + usb_init_task(&sc->sc_ledtask, urtw_ledusbtask, sc, + USB_TASK_TYPE_GENERIC); timeout_set(&sc->scan_to, urtw_next_scan, sc); timeout_set(&sc->sc_led_ch, urtw_ledtask, sc); Index: if_zyd.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_zyd.c,v retrieving revision 1.82 diff -u -p if_zyd.c --- if_zyd.c 27 Aug 2010 17:08:01 -0000 1.82 +++ if_zyd.c 17 Oct 2010 22:12:53 -0000 @@ -323,7 +323,7 @@ zyd_complete_attach(struct zyd_softc *sc) usbd_status error; int i; - usb_init_task(&sc->sc_task, zyd_task, sc); + usb_init_task(&sc->sc_task, zyd_task, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->scan_to, zyd_next_scan, sc); sc->amrr.amrr_min_success_threshold = 1; Index: ohci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/ohci.c,v retrieving revision 1.99 diff -u -p ohci.c --- ohci.c 7 Sep 2010 16:21:46 -0000 1.99 +++ ohci.c 17 Oct 2010 22:12:53 -0000 @@ -1894,7 +1894,8 @@ ohci_timeout(void *addr) } /* Execute the abort in a process context. */ - usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr); + usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr, + USB_TASK_TYPE_ABORT); usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task); } Index: udcf.c =================================================================== RCS file: /cvs/src/sys/dev/usb/udcf.c,v retrieving revision 1.48 diff -u -p udcf.c --- udcf.c 24 Sep 2010 08:33:59 -0000 1.48 +++ udcf.c 17 Oct 2010 22:12:53 -0000 @@ -206,10 +206,10 @@ udcf_attach(struct device *parent, struct device *self break; } - usb_init_task(&sc->sc_task, udcf_probe, sc); - usb_init_task(&sc->sc_bv_task, udcf_bv_probe, sc); - usb_init_task(&sc->sc_mg_task, udcf_mg_probe, sc); - usb_init_task(&sc->sc_sl_task, udcf_sl_probe, sc); + usb_init_task(&sc->sc_task, udcf_probe, sc, USB_TASK_TYPE_GENERIC); + usb_init_task(&sc->sc_bv_task, udcf_bv_probe, sc, USB_TASK_TYPE_GENERIC); + usb_init_task(&sc->sc_mg_task, udcf_mg_probe, sc, USB_TASK_TYPE_GENERIC); + usb_init_task(&sc->sc_sl_task, udcf_sl_probe, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->sc_to, udcf_intr, sc); timeout_set(&sc->sc_bv_to, udcf_bv_intr, sc); @@ -218,7 +218,8 @@ udcf_attach(struct device *parent, struct device *self timeout_set(&sc->sc_it_to, udcf_it_intr, sc); if (sc->sc_detect_ct) { - usb_init_task(&sc->sc_ct_task, udcf_ct_probe, sc); + usb_init_task(&sc->sc_ct_task, udcf_ct_probe, sc, + USB_TASK_TYPE_GENERIC); timeout_set(&sc->sc_ct_to, udcf_ct_intr, sc); } strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, Index: ueagle.c =================================================================== RCS file: /cvs/src/sys/dev/usb/ueagle.c,v retrieving revision 1.28 diff -u -p ueagle.c --- ueagle.c 24 Sep 2010 08:33:59 -0000 1.28 +++ ueagle.c 17 Oct 2010 22:12:53 -0000 @@ -210,7 +210,8 @@ ueagle_attach(struct device *parent, struct device *se sc->sc_dev.dv_xname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - usb_init_task(&sc->sc_swap_task, ueagle_loadpage, sc); + usb_init_task(&sc->sc_swap_task, ueagle_loadpage, sc, + USB_TASK_TYPE_GENERIC); ifp->if_softc = sc; ifp->if_flags = IFF_SIMPLEX; Index: uhci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uhci.c,v retrieving revision 1.83 diff -u -p uhci.c --- uhci.c 20 Sep 2010 06:54:10 -0000 1.83 +++ uhci.c 17 Oct 2010 22:12:54 -0000 @@ -1447,7 +1447,8 @@ uhci_timeout(void *addr) } /* Execute the abort in a process context. */ - usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer); + usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer, + USB_TASK_TYPE_ABORT); usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task); } Index: umbg.c =================================================================== RCS file: /cvs/src/sys/dev/usb/umbg.c,v retrieving revision 1.12 diff -u -p umbg.c --- umbg.c 24 Sep 2010 08:33:59 -0000 1.12 +++ umbg.c 17 Oct 2010 22:12:54 -0000 @@ -200,7 +200,7 @@ umbg_attach(struct device *parent, struct device *self sensor_attach(&sc->sc_sensordev, &sc->sc_signal); sensordev_install(&sc->sc_sensordev); - usb_init_task(&sc->sc_task, umbg_task, sc); + usb_init_task(&sc->sc_task, umbg_task, sc, USB_TASK_TYPE_GENERIC); timeout_set(&sc->sc_to, umbg_intr, sc); timeout_set(&sc->sc_it_to, umbg_it_intr, sc); ? usb-abort.diff Index: usb.c =================================================================== RCS file: /cvs/src/sys/dev/usb/usb.c,v retrieving revision 1.68 diff -u -p usb.c --- usb.c 23 Sep 2010 06:30:37 -0000 1.68 +++ usb.c 17 Oct 2010 22:12:54 -0000 @@ -100,17 +100,20 @@ struct usb_softc { struct timeval sc_ptime; }; +TAILQ_HEAD(, usb_task) usb_abort_tasks; TAILQ_HEAD(, usb_task) usb_explore_tasks; -TAILQ_HEAD(, usb_task) usb_tasks; +TAILQ_HEAD(, usb_task) usb_generic_tasks; -int usb_run_tasks; +int usb_run_tasks, usb_run_abort_tasks; int explore_pending; void usb_explore(void *); void usb_first_explore(void *); -void usb_create_task_thread(void *); +void usb_create_task_threads(void *); void usb_task_thread(void *); struct proc *usb_task_thread_proc = NULL; +void usb_abort_task_thread(void *); +struct proc *usb_abort_task_thread_proc = NULL; #define USB_MAX_EVENTS 100 struct usb_event_q { @@ -195,7 +198,8 @@ usb_attach(struct device *parent, struct device *self, sc->sc_bus->flags |= USB_BUS_CONFIG_PENDING; /* explore task */ - usb_init_task(&sc->sc_explore_task, usb_explore, sc); + usb_init_task(&sc->sc_explore_task, usb_explore, sc, + USB_TASK_TYPE_EXPLORE); ue.u.ue_ctrlr.ue_bus = sc->sc_dev.dv_unit; usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue); @@ -252,10 +256,11 @@ usb_attach(struct device *parent, struct device *self, void usb_begin_tasks(void) { + TAILQ_INIT(&usb_abort_tasks); TAILQ_INIT(&usb_explore_tasks); - TAILQ_INIT(&usb_tasks); - usb_run_tasks = 1; - kthread_create_deferred(usb_create_task_thread, NULL); + TAILQ_INIT(&usb_generic_tasks); + usb_run_tasks = usb_run_abort_tasks = 1; + kthread_create_deferred(usb_create_task_threads, NULL); } /* @@ -264,13 +269,18 @@ usb_begin_tasks(void) void usb_end_tasks(void) { - usb_run_tasks = 0; + usb_run_tasks = usb_run_abort_tasks = 0; + wakeup(&usb_run_abort_tasks); wakeup(&usb_run_tasks); } void -usb_create_task_thread(void *arg) +usb_create_task_threads(void *arg) { + if (kthread_create(usb_abort_task_thread, NULL, + &usb_abort_task_thread_proc, "usbatsk")) + panic("unable to create usb abort task thread"); + if (kthread_create(usb_task_thread, NULL, &usb_task_thread_proc, "usbtask")) panic("unable to create usb task thread"); @@ -286,7 +296,8 @@ usb_add_task(usbd_device_handle dev, struct usb_task * { int s; - DPRINTFN(2,("%s: task=%p onqueue=%d\n", __func__, task, task->onqueue)); + DPRINTFN(2,("%s: task=%p onqueue=%d type=%d\n", __func__, task, + task->onqueue, task->type)); /* Don't add task if the device's root hub is dying. */ if (dev->bus->dying) @@ -294,14 +305,24 @@ usb_add_task(usbd_device_handle dev, struct usb_task * s = splusb(); if (!task->onqueue) { - if (task->fun == usb_explore) + switch (task->type) { + case USB_TASK_TYPE_ABORT: + TAILQ_INSERT_TAIL(&usb_abort_tasks, task, next); + break; + case USB_TASK_TYPE_EXPLORE: TAILQ_INSERT_TAIL(&usb_explore_tasks, task, next); - else - TAILQ_INSERT_TAIL(&usb_tasks, task, next); + break; + case USB_TASK_TYPE_GENERIC: + TAILQ_INSERT_TAIL(&usb_generic_tasks, task, next); + break; + } task->onqueue = 1; task->dev = dev; } - wakeup(&usb_run_tasks); + if (task->type == USB_TASK_TYPE_ABORT) + wakeup(&usb_run_abort_tasks); + else + wakeup(&usb_run_tasks); splx(s); } @@ -310,14 +331,22 @@ usb_rem_task(usbd_device_handle dev, struct usb_task * { int s; - DPRINTFN(2,("%s: task=%p onqueue=%d\n", __func__, task, task->onqueue)); + DPRINTFN(2,("%s: task=%p onqueue=%d type=%d\n", __func__, task, + task->onqueue, task->type)); s = splusb(); if (task->onqueue) { - if (task->fun == usb_explore) + switch (task->type) { + case USB_TASK_TYPE_ABORT: + TAILQ_REMOVE(&usb_abort_tasks, task, next); + break; + case USB_TASK_TYPE_EXPLORE: TAILQ_REMOVE(&usb_explore_tasks, task, next); - else - TAILQ_REMOVE(&usb_tasks, task, next); + break; + case USB_TASK_TYPE_GENERIC: + TAILQ_REMOVE(&usb_generic_tasks, task, next); + break; + } task->onqueue = 0; } splx(s); @@ -328,7 +357,8 @@ usb_rem_wait_task(usbd_device_handle dev, struct usb_t { int s; - DPRINTFN(2,("%s: task=%p onqueue=%d\n", __func__, task, task->onqueue)); + DPRINTFN(2,("%s: task=%p onqueue=%d type=%d\n", __func__, task, + task->onqueue, task->type)); s = splusb(); usb_rem_task(dev, task); @@ -391,10 +421,47 @@ usb_task_thread(void *arg) while (usb_run_tasks) { if ((task = TAILQ_FIRST(&usb_explore_tasks)) != NULL) TAILQ_REMOVE(&usb_explore_tasks, task, next); - else if ((task = TAILQ_FIRST(&usb_tasks)) != NULL) - TAILQ_REMOVE(&usb_tasks, task, next); + else if ((task = TAILQ_FIRST(&usb_generic_tasks)) != NULL) + TAILQ_REMOVE(&usb_generic_tasks, task, next); else { tsleep(&usb_run_tasks, PWAIT, "usbtsk", 0); + continue; + } + task->onqueue = 0; + /* Don't execute the task if the root hub is gone. */ + if (task->dev->bus->dying) + continue; + task->running = 1; + splx(s); + task->fun(task->arg); + s = splusb(); + task->running = 0; + wakeup(task); + } + splx(s); + + kthread_exit(0); +} + +/* + * This thread is ONLY for the HCI drivers to be able to abort xfers. + * Synchronous xfers sleep the task thread, so the aborts need to happen + * in a different thread. + */ +void +usb_abort_task_thread(void *arg) +{ + struct usb_task *task; + int s; + + DPRINTF(("usb_xfer_abort_thread: start\n")); + + s = splusb(); + while (usb_run_abort_tasks) { + if ((task = TAILQ_FIRST(&usb_abort_tasks)) != NULL) + TAILQ_REMOVE(&usb_abort_tasks, task, next); + else { + tsleep(&usb_run_abort_tasks, PWAIT, "usbatsk", 0); continue; } task->onqueue = 0; Index: usbdi.h =================================================================== RCS file: /cvs/src/sys/dev/usb/usbdi.h,v retrieving revision 1.34 diff -u -p usbdi.h --- usbdi.h 23 Sep 2010 06:30:37 -0000 1.34 +++ usbdi.h 17 Oct 2010 22:12:54 -0000 @@ -184,6 +184,10 @@ struct usb_task { usbd_device_handle dev; void (*fun)(void *); void *arg; + char type; +#define USB_TASK_TYPE_GENERIC 0 +#define USB_TASK_TYPE_EXPLORE 1 +#define USB_TASK_TYPE_ABORT 2 char onqueue; char running; }; @@ -191,7 +195,12 @@ struct usb_task { void usb_add_task(usbd_device_handle, struct usb_task *); void usb_rem_task(usbd_device_handle, struct usb_task *); void usb_rem_wait_task(usbd_device_handle, struct usb_task *); -#define usb_init_task(t, f, a) ((t)->fun = (f), (t)->arg = (a), (t)->onqueue = 0, (t)->running = 0) +#define usb_init_task(t, f, a, y) \ + ((t)->fun = (f), \ + (t)->arg = (a), \ + (t)->type = (y), \ + (t)->onqueue = 0, \ + (t)->running = 0) struct usb_devno { u_int16_t ud_vendor; Index: uvideo.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uvideo.c,v retrieving revision 1.142 diff -u -p uvideo.c --- uvideo.c 9 Oct 2010 09:48:03 -0000 1.142 +++ uvideo.c 17 Oct 2010 22:12:54 -0000 @@ -1795,7 +1795,8 @@ uvideo_vs_init(struct uvideo_softc *sc) #ifdef UVIDEO_DUMP if (uvideo_debug_file_open(sc) != 0) return (USBD_INVAL); - usb_init_task(&sc->sc_task_write, uvideo_debug_file_write_frame, sc); + usb_init_task(&sc->sc_task_write, uvideo_debug_file_write_frame, sc, + USB_TASK_TYPE_GENERIC); #endif return (USBD_NORMAL_COMPLETION); }
