diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index 95be9953cd47..cc74d669c802 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -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); } diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h index 2384add45371..41838db7f85c 100644 --- a/drivers/usb/wusbcore/wusbhc.h +++ b/drivers/usb/wusbcore/wusbhc.h @@ -295,6 +295,9 @@ struct wusbhc { } __attribute__((packed)) gtk; u8 gtk_index; u32 gtk_tkid; + + /* workqueue for WUSB security related tasks. */ + struct workqueue_struct *wq_security; struct work_struct gtk_rekey_work; struct usb_encryption_descriptor *ccm1_etd;