|
@@ -33,6 +33,20 @@ static void wusbhc_gtk_rekey_work(struct work_struct *work);
|
|
|
|
|
|
int wusbhc_sec_create(struct wusbhc *wusbhc)
|
|
|
{
|
|
|
+ /*
|
|
|
+ * WQ is singlethread because we need to serialize rekey operations.
|
|
|
+ * Use a separate workqueue for security operations instead of the
|
|
|
+ * wusbd workqueue because security operations may need to communicate
|
|
|
+ * directly with downstream wireless devices using synchronous URBs.
|
|
|
+ * If a device is not responding, this could block other host
|
|
|
+ * controller operations.
|
|
|
+ */
|
|
|
+ wusbhc->wq_security = create_singlethread_workqueue("wusbd_security");
|
|
|
+ if (wusbhc->wq_security == NULL) {
|
|
|
+ pr_err("WUSB-core: Cannot create wusbd_security workqueue\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) +
|
|
|
sizeof(wusbhc->gtk.data);
|
|
|
wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;
|
|
@@ -48,6 +62,7 @@ int wusbhc_sec_create(struct wusbhc *wusbhc)
|
|
|
/* Called when the HC is destroyed */
|
|
|
void wusbhc_sec_destroy(struct wusbhc *wusbhc)
|
|
|
{
|
|
|
+ destroy_workqueue(wusbhc->wq_security);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -596,5 +611,5 @@ void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
|
|
|
* and will cause a deadlock. Instead, queue a work item to do
|
|
|
* it when the lock is not held
|
|
|
*/
|
|
|
- queue_work(wusbd, &wusbhc->gtk_rekey_work);
|
|
|
+ queue_work(wusbhc->wq_security, &wusbhc->gtk_rekey_work);
|
|
|
}
|