diff --git a/arch/arm/src/lpc31xx/lpc31_ehci.c b/arch/arm/src/lpc31xx/lpc31_ehci.c index 49dc9a615d2..636d97ba2b6 100644 --- a/arch/arm/src/lpc31xx/lpc31_ehci.c +++ b/arch/arm/src/lpc31xx/lpc31_ehci.c @@ -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? */ diff --git a/arch/arm/src/sama5/sam_ehci.c b/arch/arm/src/sama5/sam_ehci.c index 22a12645f8b..6165a029d1e 100644 --- a/arch/arm/src/sama5/sam_ehci.c +++ b/arch/arm/src/sama5/sam_ehci.c @@ -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 diff --git a/configs/olimex-lpc-h3131/README.txt b/configs/olimex-lpc-h3131/README.txt index 5f3b47fd225..2999f6e960c 100644 --- a/configs/olimex-lpc-h3131/README.txt +++ b/configs/olimex-lpc-h3131/README.txt @@ -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 - Logic nesting becomes deeper with a hub and it may also be - necessary to increase some stack sizes. + 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. + + 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 diff --git a/configs/olimex-lpc1766stk/README.txt b/configs/olimex-lpc1766stk/README.txt index f5e138f8f58..9f013df8926 100644 --- a/configs/olimex-lpc1766stk/README.txt +++ b/configs/olimex-lpc1766stk/README.txt @@ -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 + Drivers -> USB Host Driver Support + 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 + 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 - I also increased some stack sizes: + RTOS Features -> Work Queue Support + CONFIG_SCHED_LPWORK=y : Low priority queue support is needed + CONFIG_SCHED_LPNTHREADS=1 + CONFIG_SCHED_LPWORKSTACKSIZE=1024 - CONFIG_EXAMPLES_HIDKBD_STACKSIZE=2048 : Was 1024 - CONFIG_HIDKBD_STACKSIZE=2048 : Was 1024 - CONFIG_SCHED_HPWORKSTACKSIZE=2048 : Was 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 diff --git a/drivers/usbhost/usbhost_hub.c b/drivers/usbhost/usbhost_hub.c index e6ab974ae83..0ad2170a901 100644 --- a/drivers/usbhost/usbhost_hub.c +++ b/drivers/usbhost/usbhost_hub.c @@ -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;