15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 296c27377SValentina Manea /* 396c27377SValentina Manea * Copyright (C) 2003-2008 Takahiro Hirofuchi 4bb7871adSNobuo Iwata * Copyright (C) 2015 Nobuo Iwata 596c27377SValentina Manea */ 696c27377SValentina Manea 796c27377SValentina Manea #include <linux/kthread.h> 896c27377SValentina Manea #include <linux/export.h> 9bb7871adSNobuo Iwata #include <linux/slab.h> 10bb7871adSNobuo Iwata #include <linux/workqueue.h> 1196c27377SValentina Manea 1296c27377SValentina Manea #include "usbip_common.h" 1396c27377SValentina Manea 14bb7871adSNobuo Iwata struct usbip_event { 15bb7871adSNobuo Iwata struct list_head node; 16bb7871adSNobuo Iwata struct usbip_device *ud; 17bb7871adSNobuo Iwata }; 1896c27377SValentina Manea 19bb7871adSNobuo Iwata static DEFINE_SPINLOCK(event_lock); 20bb7871adSNobuo Iwata static LIST_HEAD(event_list); 21bb7871adSNobuo Iwata 22bb7871adSNobuo Iwata static void set_event(struct usbip_device *ud, unsigned long event) 23bb7871adSNobuo Iwata { 24bb7871adSNobuo Iwata unsigned long flags; 25bb7871adSNobuo Iwata 26bb7871adSNobuo Iwata spin_lock_irqsave(&ud->lock, flags); 27bb7871adSNobuo Iwata ud->event |= event; 28bb7871adSNobuo Iwata spin_unlock_irqrestore(&ud->lock, flags); 29bb7871adSNobuo Iwata } 30bb7871adSNobuo Iwata 31bb7871adSNobuo Iwata static void unset_event(struct usbip_device *ud, unsigned long event) 32bb7871adSNobuo Iwata { 33bb7871adSNobuo Iwata unsigned long flags; 34bb7871adSNobuo Iwata 35bb7871adSNobuo Iwata spin_lock_irqsave(&ud->lock, flags); 36bb7871adSNobuo Iwata ud->event &= ~event; 37bb7871adSNobuo Iwata spin_unlock_irqrestore(&ud->lock, flags); 38bb7871adSNobuo Iwata } 39bb7871adSNobuo Iwata 40bb7871adSNobuo Iwata static struct usbip_device *get_event(void) 41bb7871adSNobuo Iwata { 42bb7871adSNobuo Iwata struct usbip_event *ue = NULL; 43bb7871adSNobuo Iwata struct usbip_device *ud = NULL; 44bb7871adSNobuo Iwata unsigned long flags; 45bb7871adSNobuo Iwata 46bb7871adSNobuo Iwata spin_lock_irqsave(&event_lock, flags); 47bb7871adSNobuo Iwata if (!list_empty(&event_list)) { 48bb7871adSNobuo Iwata ue = list_first_entry(&event_list, struct usbip_event, node); 49bb7871adSNobuo Iwata list_del(&ue->node); 50bb7871adSNobuo Iwata } 51bb7871adSNobuo Iwata spin_unlock_irqrestore(&event_lock, flags); 52bb7871adSNobuo Iwata 53bb7871adSNobuo Iwata if (ue) { 54bb7871adSNobuo Iwata ud = ue->ud; 55bb7871adSNobuo Iwata kfree(ue); 56bb7871adSNobuo Iwata } 57bb7871adSNobuo Iwata return ud; 58bb7871adSNobuo Iwata } 59bb7871adSNobuo Iwata 60bb7871adSNobuo Iwata static struct task_struct *worker_context; 61bb7871adSNobuo Iwata 62bb7871adSNobuo Iwata static void event_handler(struct work_struct *work) 63bb7871adSNobuo Iwata { 64bb7871adSNobuo Iwata struct usbip_device *ud; 65bb7871adSNobuo Iwata 66bb7871adSNobuo Iwata if (worker_context == NULL) { 67bb7871adSNobuo Iwata worker_context = current; 68bb7871adSNobuo Iwata } 69bb7871adSNobuo Iwata 70bb7871adSNobuo Iwata while ((ud = get_event()) != NULL) { 7196c27377SValentina Manea usbip_dbg_eh("pending event %lx\n", ud->event); 7296c27377SValentina Manea 73*363eaa3aSShuah Khan mutex_lock(&ud->sysfs_lock); 7496c27377SValentina Manea /* 7596c27377SValentina Manea * NOTE: shutdown must come first. 7696c27377SValentina Manea * Shutdown the device. 7796c27377SValentina Manea */ 7896c27377SValentina Manea if (ud->event & USBIP_EH_SHUTDOWN) { 7996c27377SValentina Manea ud->eh_ops.shutdown(ud); 80bb7871adSNobuo Iwata unset_event(ud, USBIP_EH_SHUTDOWN); 8196c27377SValentina Manea } 8296c27377SValentina Manea 8396c27377SValentina Manea /* Reset the device. */ 8496c27377SValentina Manea if (ud->event & USBIP_EH_RESET) { 8596c27377SValentina Manea ud->eh_ops.reset(ud); 86bb7871adSNobuo Iwata unset_event(ud, USBIP_EH_RESET); 8796c27377SValentina Manea } 8896c27377SValentina Manea 8996c27377SValentina Manea /* Mark the device as unusable. */ 9096c27377SValentina Manea if (ud->event & USBIP_EH_UNUSABLE) { 9196c27377SValentina Manea ud->eh_ops.unusable(ud); 92bb7871adSNobuo Iwata unset_event(ud, USBIP_EH_UNUSABLE); 9396c27377SValentina Manea } 94*363eaa3aSShuah Khan mutex_unlock(&ud->sysfs_lock); 9596c27377SValentina Manea 96bb7871adSNobuo Iwata wake_up(&ud->eh_waitq); 9796c27377SValentina Manea } 9896c27377SValentina Manea } 9996c27377SValentina Manea 10096c27377SValentina Manea int usbip_start_eh(struct usbip_device *ud) 10196c27377SValentina Manea { 10296c27377SValentina Manea init_waitqueue_head(&ud->eh_waitq); 10396c27377SValentina Manea ud->event = 0; 10496c27377SValentina Manea return 0; 10596c27377SValentina Manea } 10696c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_start_eh); 10796c27377SValentina Manea 10896c27377SValentina Manea void usbip_stop_eh(struct usbip_device *ud) 10996c27377SValentina Manea { 110bb7871adSNobuo Iwata unsigned long pending = ud->event & ~USBIP_EH_BYE; 11196c27377SValentina Manea 112bb7871adSNobuo Iwata if (!(ud->event & USBIP_EH_BYE)) 113bb7871adSNobuo Iwata usbip_dbg_eh("usbip_eh stopping but not removed\n"); 114bb7871adSNobuo Iwata 115bb7871adSNobuo Iwata if (pending) 116bb7871adSNobuo Iwata usbip_dbg_eh("usbip_eh waiting completion %lx\n", pending); 117bb7871adSNobuo Iwata 118bb7871adSNobuo Iwata wait_event_interruptible(ud->eh_waitq, !(ud->event & ~USBIP_EH_BYE)); 119bb7871adSNobuo Iwata usbip_dbg_eh("usbip_eh has stopped\n"); 12096c27377SValentina Manea } 12196c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_stop_eh); 12296c27377SValentina Manea 123bb7871adSNobuo Iwata #define WORK_QUEUE_NAME "usbip_event" 124bb7871adSNobuo Iwata 125bb7871adSNobuo Iwata static struct workqueue_struct *usbip_queue; 126bb7871adSNobuo Iwata static DECLARE_WORK(usbip_work, event_handler); 127bb7871adSNobuo Iwata 128bb7871adSNobuo Iwata int usbip_init_eh(void) 129bb7871adSNobuo Iwata { 130bb7871adSNobuo Iwata usbip_queue = create_singlethread_workqueue(WORK_QUEUE_NAME); 131bb7871adSNobuo Iwata if (usbip_queue == NULL) { 132bb7871adSNobuo Iwata pr_err("failed to create usbip_event\n"); 133bb7871adSNobuo Iwata return -ENOMEM; 134bb7871adSNobuo Iwata } 135bb7871adSNobuo Iwata return 0; 136bb7871adSNobuo Iwata } 137bb7871adSNobuo Iwata 138bb7871adSNobuo Iwata void usbip_finish_eh(void) 139bb7871adSNobuo Iwata { 140bb7871adSNobuo Iwata flush_workqueue(usbip_queue); 141bb7871adSNobuo Iwata destroy_workqueue(usbip_queue); 142bb7871adSNobuo Iwata usbip_queue = NULL; 143bb7871adSNobuo Iwata } 144bb7871adSNobuo Iwata 14596c27377SValentina Manea void usbip_event_add(struct usbip_device *ud, unsigned long event) 14696c27377SValentina Manea { 147bb7871adSNobuo Iwata struct usbip_event *ue; 14896c27377SValentina Manea unsigned long flags; 14996c27377SValentina Manea 150bb7871adSNobuo Iwata if (ud->event & USBIP_EH_BYE) 151bb7871adSNobuo Iwata return; 152bb7871adSNobuo Iwata 153bb7871adSNobuo Iwata set_event(ud, event); 154bb7871adSNobuo Iwata 155bb7871adSNobuo Iwata spin_lock_irqsave(&event_lock, flags); 156bb7871adSNobuo Iwata 157bb7871adSNobuo Iwata list_for_each_entry_reverse(ue, &event_list, node) { 158bb7871adSNobuo Iwata if (ue->ud == ud) 159bb7871adSNobuo Iwata goto out; 160bb7871adSNobuo Iwata } 161bb7871adSNobuo Iwata 162bb7871adSNobuo Iwata ue = kmalloc(sizeof(struct usbip_event), GFP_ATOMIC); 163bb7871adSNobuo Iwata if (ue == NULL) 164bb7871adSNobuo Iwata goto out; 165bb7871adSNobuo Iwata 166bb7871adSNobuo Iwata ue->ud = ud; 167bb7871adSNobuo Iwata 168bb7871adSNobuo Iwata list_add_tail(&ue->node, &event_list); 169bb7871adSNobuo Iwata queue_work(usbip_queue, &usbip_work); 170bb7871adSNobuo Iwata 171bb7871adSNobuo Iwata out: 172bb7871adSNobuo Iwata spin_unlock_irqrestore(&event_lock, flags); 17396c27377SValentina Manea } 17496c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_event_add); 17596c27377SValentina Manea 17696c27377SValentina Manea int usbip_event_happened(struct usbip_device *ud) 17796c27377SValentina Manea { 17896c27377SValentina Manea int happened = 0; 17921619792SAndrew Goodbody unsigned long flags; 18096c27377SValentina Manea 18121619792SAndrew Goodbody spin_lock_irqsave(&ud->lock, flags); 18296c27377SValentina Manea if (ud->event != 0) 18396c27377SValentina Manea happened = 1; 18421619792SAndrew Goodbody spin_unlock_irqrestore(&ud->lock, flags); 18596c27377SValentina Manea 18696c27377SValentina Manea return happened; 18796c27377SValentina Manea } 18896c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_event_happened); 189bb7871adSNobuo Iwata 190bb7871adSNobuo Iwata int usbip_in_eh(struct task_struct *task) 191bb7871adSNobuo Iwata { 192bb7871adSNobuo Iwata if (task == worker_context) 193bb7871adSNobuo Iwata return 1; 194bb7871adSNobuo Iwata 195bb7871adSNobuo Iwata return 0; 196bb7871adSNobuo Iwata } 197bb7871adSNobuo Iwata EXPORT_SYMBOL_GPL(usbip_in_eh); 198