Skip to content
Snippets Groups Projects
Commit b909ad04 authored by Gregory Nutt's avatar Gregory Nutt
Browse files

USB HUB: Fix a deadlock that can occur if the HCD and the HUB try to share the...

USB HUB: Fix a deadlock that can occur if the HCD and the HUB try to share the high priority work queue.  Now how work must be done on the low priority work queue.
parent 086bb52a
No related branches found
No related tags found
No related merge requests found
......@@ -73,8 +73,10 @@
/* Configuration ***************************************************************/
/* Pre-requisites */
#ifndef CONFIG_SCHED_WORKQUEUE
#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required (CONFIG_SCHED_WORKQUEUE)
#elif !defined(CONFIG_SCHED_HPWORK)
# error Hi-priority work queue support is required (CONFIG_SCHED_HPWORK)
#endif
/* Configurable number of Queue Head (QH) structures. The default is one per
......@@ -2570,7 +2572,7 @@ static inline int lpc31_asynch_setup(struct lpc31_rhport_s *rhport,
int ret = -ENODEV;
DEBUGASSERT(rhport && epinfo && !epinfo->iocwait &&
epinfo->callback == NULL);
callback != NULL && epinfo->callback == NULL);
/* Is the device still connected? */
......
......@@ -73,8 +73,10 @@
/* Configuration ***************************************************************/
/* Pre-requisites */
#ifndef CONFIG_SCHED_WORKQUEUE
#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required (CONFIG_SCHED_WORKQUEUE)
#elif !defined(CONFIG_SCHED_HPWORK)
# error Hi-priority work queue support is required (CONFIG_SCHED_HPWORK)
#endif
/* Configurable number of Queue Head (QH) structures. The default is one per
......
......@@ -668,8 +668,9 @@ Configurations
CONFIG_LPC31_EHCI_PREALLOCATE=y
RTOS Features -> Work Queue Support
CONFIG_SCHED_WORKQUEUE=y : Work queue support is needed
CONFIG_SCHED_HPWORKSTACKSIZE=1536
CONFIG_SCHED_WORKQUEUE=y : High priority queue support is needed
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_HPWORKSTACKSIZE=1536 (1024 seems to work okay too)
b. Hub Support.
......@@ -678,11 +679,26 @@ Configurations
CONFIG_USBHOST_HUB=y : Enable the hub class
CONFIG_USBHOST_ASYNCH=y : Asynchronous I/O supported needed for hubs
System Type -> USB host configuration
To be provided
RTOS Features -> Work Queue Support
CONFIG_SCHED_LPWORK=y : Low priority queue support is needed
CONFIG_SCHED_LPNTHREADS=1
CONFIG_SCHED_LPWORKSTACKSIZE=1024
NOTES:
1. It is necessary to perform work on the low-priority work queue
(vs. the high priority work queue) because:
a. Deferred work requires some delays and waiting, and
b. There are dependencies between the waiting and driver
interrupt related work. Since that interrupt related work
will performed on the high priority work queue, there would
be the likelihood of deadlocks if you wait for events on the
high priority work thread that can only occur if the high
priority work thread is available to post those events.
Logic nesting becomes deeper with a hub and it may also be
necessary to increase some stack sizes.
2. Logic nesting becomes deeper with a hub and it may also be
necessary to increase some stack sizes.
c. USB Mass Storage Class. With this class enabled, you can support
connection of USB FLASH storage drives. Support for the USB
......
......@@ -955,20 +955,36 @@ Configuration Sub-Directories
2. I used this configuration to test the USB hub class. I did this
testing with the following changes to the configuration:
CONFIG_USBHOST_HUB=y : Enable the hub class
CONFIG_USBHOST_ASYNCH=y : Asynchonous I/O supported needed for hubs
CONFIG_LPC17_USBHOST_NASYNCH=8 : Allow up to 8 asynchronous requests
CONFIG_USBHOST_NEDS=3 : Increase number of endpoint descriptors from 2
CONFIG_USBHOST_NTDS=4 : Increase number of transfer descriptors from 3
CONFIG_USBHOST_TDBUFFERS=4 : Increase number of transfer buffers from 3
CONFIG_USBHOST_IOBUFSIZE=256 : Decrease the size of I/O buffers from 512
I also increased some stack sizes:
CONFIG_EXAMPLES_HIDKBD_STACKSIZE=2048 : Was 1024
CONFIG_HIDKBD_STACKSIZE=2048 : Was 1024
CONFIG_SCHED_HPWORKSTACKSIZE=2048 : Was 1024
Drivers -> USB Host Driver Support
CONFIG_USBHOST_HUB=y : Enable the hub class
CONFIG_USBHOST_ASYNCH=y : Asynchonous I/O supported needed for hubs
System Type -> USB host configuration
CONFIG_LPC17_USBHOST_NASYNCH=8 : Allow up to 8 asynchronous requests
CONFIG_USBHOST_NEDS=3 : Increase number of endpoint descriptors from 2
CONFIG_USBHOST_NTDS=4 : Increase number of transfer descriptors from 3
CONFIG_USBHOST_TDBUFFERS=4 : Increase number of transfer buffers from 3
CONFIG_USBHOST_IOBUFSIZE=256 : Decrease the size of I/O buffers from 512
RTOS Features -> Work Queue Support
CONFIG_SCHED_LPWORK=y : Low priority queue support is needed
CONFIG_SCHED_LPNTHREADS=1
CONFIG_SCHED_LPWORKSTACKSIZE=1024
NOTES:
1. It is necessary to perform work on the low-priority work queue
(vs. the high priority work queue) because deferred hub-related
work requires some delays and waiting that is not appropriate on
the high priority work queue.
2. I also increased some stack sizes. These values are not tuned.
When I ran into stack size issues, I just increased the size of
all threads that had smaller stacks.
CONFIG_EXAMPLES_HIDKBD_STACKSIZE=2048 : Was 1024
CONFIG_HIDKBD_STACKSIZE=2048 : Was 1024
CONFIG_SCHED_HPWORKSTACKSIZE=2048 : Was 1024 (1024 is probably ok)
STATUS:
2015-04-26: The hub basically works. I do get crashes in the LPC16 USB host driver
......
......@@ -65,29 +65,29 @@
****************************************************************************/
/* Configuration ************************************************************/
/* It is necessary to perform work on the low-priority work queue (vs. the
* high priority work queue) because:
*
* 1. Deferred work requires some delays and waiting, and
* 2. There may be dependencies between the waiting and driver interrupt
* related work. Since that interrupt related work will performed on the
* high priority work queue, there would be the likelihood of deadlocks
* if you wait for events on the high priority work thread that can only
* occur if the high priority work thread is available to post those events.
*/
#ifndef CONFIG_SCHED_WORKQUEUE
# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required (CONFIG_SCHED_WORKQUEUE)
#elif !defined(CONFIG_SCHED_LPWORK)
# error Low-priority work queue support is required (CONFIG_SCHED_LPWORK)
#endif
/* Perform polling actions on the low priority work queue, if configured */
#ifndef CONFIG_SCHED_LPWORK
# define POLL_WORK LPWORK
#else
# define POLL_WORK HPWORK
#endif
/* Perform polling actions with a delay on the low priority work queue, if
* configured
*/
#define POLL_DELAY MSEC2TICK(400)
/* Perform event processing on the high priority work queue, if configured */
#ifndef CONFIG_SCHED_HPWORK
# define EVENT_WORK HPWORK
#else
# define EVENT_WORK LPWORK
#endif
/* Used in usbhost_cfgdesc() */
#define USBHOST_IFFOUND 0x01 /* Required I/F descriptor found */
......@@ -1013,10 +1013,7 @@ static void usbhost_disconnect_event(FAR void *arg)
/* Cancel any pending port status change events */
work_cancel(EVENT_WORK, &priv->work);
#if EVENT_WORK != POLL_WORK
work_cancel(POLL_WORK, &priv->work);
#endif
work_cancel(LPWORK, &priv->work);
/* Disable power to all downstream ports */
......@@ -1130,7 +1127,6 @@ static void usbhost_callback(FAR void *arg, int result)
FAR struct usbhost_class_s *hubclass;
FAR struct usbhost_hubpriv_s *priv;
uint32_t delay = 0;
int qid = EVENT_WORK;
DEBUGASSERT(arg != NULL);
hubclass = (FAR struct usbhost_class_s *)arg;
......@@ -1157,7 +1153,6 @@ static void usbhost_callback(FAR void *arg, int result)
* case.
*/
qid = POLL_WORK;
delay = POLL_DELAY;
}
......@@ -1168,7 +1163,7 @@ static void usbhost_callback(FAR void *arg, int result)
if (work_available(&priv->work))
{
(void)work_queue(qid, &priv->work, (worker_t)usbhost_hub_event,
(void)work_queue(LPWORK, &priv->work, (worker_t)usbhost_hub_event,
hubclass, delay);
}
}
......@@ -1419,7 +1414,7 @@ static int usbhost_disconnected(struct usbhost_class_s *hubclass)
*/
flags = irqsave();
ret = work_queue(EVENT_WORK, &priv->work,
ret = work_queue(LPWORK, &priv->work,
(worker_t)usbhost_disconnect_event, hubclass, 0);
irqrestore(flags);
return ret;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment