xref: /openbmc/linux/drivers/usb/usbip/usbip_event.c (revision 5fd54ace4721fc5ce2bb5aef6318fcf17f421460)
1*5fd54aceSGreg 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  * This is free software; you can redistribute it and/or modify
796c27377SValentina Manea  * it under the terms of the GNU General Public License as published by
896c27377SValentina Manea  * the Free Software Foundation; either version 2 of the License, or
996c27377SValentina Manea  * (at your option) any later version.
1096c27377SValentina Manea  *
1196c27377SValentina Manea  * This is distributed in the hope that it will be useful,
1296c27377SValentina Manea  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1396c27377SValentina Manea  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1496c27377SValentina Manea  * GNU General Public License for more details.
1596c27377SValentina Manea  *
1696c27377SValentina Manea  * You should have received a copy of the GNU General Public License
1796c27377SValentina Manea  * along with this program; if not, write to the Free Software
1896c27377SValentina Manea  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
1996c27377SValentina Manea  * USA.
2096c27377SValentina Manea  */
2196c27377SValentina Manea 
2296c27377SValentina Manea #include <linux/kthread.h>
2396c27377SValentina Manea #include <linux/export.h>
24bb7871adSNobuo Iwata #include <linux/slab.h>
25bb7871adSNobuo Iwata #include <linux/workqueue.h>
2696c27377SValentina Manea 
2796c27377SValentina Manea #include "usbip_common.h"
2896c27377SValentina Manea 
29bb7871adSNobuo Iwata struct usbip_event {
30bb7871adSNobuo Iwata 	struct list_head node;
31bb7871adSNobuo Iwata 	struct usbip_device *ud;
32bb7871adSNobuo Iwata };
3396c27377SValentina Manea 
34bb7871adSNobuo Iwata static DEFINE_SPINLOCK(event_lock);
35bb7871adSNobuo Iwata static LIST_HEAD(event_list);
36bb7871adSNobuo Iwata 
37bb7871adSNobuo Iwata static void set_event(struct usbip_device *ud, unsigned long event)
38bb7871adSNobuo Iwata {
39bb7871adSNobuo Iwata 	unsigned long flags;
40bb7871adSNobuo Iwata 
41bb7871adSNobuo Iwata 	spin_lock_irqsave(&ud->lock, flags);
42bb7871adSNobuo Iwata 	ud->event |= event;
43bb7871adSNobuo Iwata 	spin_unlock_irqrestore(&ud->lock, flags);
44bb7871adSNobuo Iwata }
45bb7871adSNobuo Iwata 
46bb7871adSNobuo Iwata static void unset_event(struct usbip_device *ud, unsigned long event)
47bb7871adSNobuo Iwata {
48bb7871adSNobuo Iwata 	unsigned long flags;
49bb7871adSNobuo Iwata 
50bb7871adSNobuo Iwata 	spin_lock_irqsave(&ud->lock, flags);
51bb7871adSNobuo Iwata 	ud->event &= ~event;
52bb7871adSNobuo Iwata 	spin_unlock_irqrestore(&ud->lock, flags);
53bb7871adSNobuo Iwata }
54bb7871adSNobuo Iwata 
55bb7871adSNobuo Iwata static struct usbip_device *get_event(void)
56bb7871adSNobuo Iwata {
57bb7871adSNobuo Iwata 	struct usbip_event *ue = NULL;
58bb7871adSNobuo Iwata 	struct usbip_device *ud = NULL;
59bb7871adSNobuo Iwata 	unsigned long flags;
60bb7871adSNobuo Iwata 
61bb7871adSNobuo Iwata 	spin_lock_irqsave(&event_lock, flags);
62bb7871adSNobuo Iwata 	if (!list_empty(&event_list)) {
63bb7871adSNobuo Iwata 		ue = list_first_entry(&event_list, struct usbip_event, node);
64bb7871adSNobuo Iwata 		list_del(&ue->node);
65bb7871adSNobuo Iwata 	}
66bb7871adSNobuo Iwata 	spin_unlock_irqrestore(&event_lock, flags);
67bb7871adSNobuo Iwata 
68bb7871adSNobuo Iwata 	if (ue) {
69bb7871adSNobuo Iwata 		ud = ue->ud;
70bb7871adSNobuo Iwata 		kfree(ue);
71bb7871adSNobuo Iwata 	}
72bb7871adSNobuo Iwata 	return ud;
73bb7871adSNobuo Iwata }
74bb7871adSNobuo Iwata 
75bb7871adSNobuo Iwata static struct task_struct *worker_context;
76bb7871adSNobuo Iwata 
77bb7871adSNobuo Iwata static void event_handler(struct work_struct *work)
78bb7871adSNobuo Iwata {
79bb7871adSNobuo Iwata 	struct usbip_device *ud;
80bb7871adSNobuo Iwata 
81bb7871adSNobuo Iwata 	if (worker_context == NULL) {
82bb7871adSNobuo Iwata 		worker_context = current;
83bb7871adSNobuo Iwata 	}
84bb7871adSNobuo Iwata 
85bb7871adSNobuo Iwata 	while ((ud = get_event()) != NULL) {
8696c27377SValentina Manea 		usbip_dbg_eh("pending event %lx\n", ud->event);
8796c27377SValentina Manea 
8896c27377SValentina Manea 		/*
8996c27377SValentina Manea 		 * NOTE: shutdown must come first.
9096c27377SValentina Manea 		 * Shutdown the device.
9196c27377SValentina Manea 		 */
9296c27377SValentina Manea 		if (ud->event & USBIP_EH_SHUTDOWN) {
9396c27377SValentina Manea 			ud->eh_ops.shutdown(ud);
94bb7871adSNobuo Iwata 			unset_event(ud, USBIP_EH_SHUTDOWN);
9596c27377SValentina Manea 		}
9696c27377SValentina Manea 
9796c27377SValentina Manea 		/* Reset the device. */
9896c27377SValentina Manea 		if (ud->event & USBIP_EH_RESET) {
9996c27377SValentina Manea 			ud->eh_ops.reset(ud);
100bb7871adSNobuo Iwata 			unset_event(ud, USBIP_EH_RESET);
10196c27377SValentina Manea 		}
10296c27377SValentina Manea 
10396c27377SValentina Manea 		/* Mark the device as unusable. */
10496c27377SValentina Manea 		if (ud->event & USBIP_EH_UNUSABLE) {
10596c27377SValentina Manea 			ud->eh_ops.unusable(ud);
106bb7871adSNobuo Iwata 			unset_event(ud, USBIP_EH_UNUSABLE);
10796c27377SValentina Manea 		}
10896c27377SValentina Manea 
10996c27377SValentina Manea 		/* Stop the error handler. */
11096c27377SValentina Manea 		if (ud->event & USBIP_EH_BYE)
111bb7871adSNobuo Iwata 			usbip_dbg_eh("removed %p\n", ud);
112bb7871adSNobuo Iwata 
113bb7871adSNobuo Iwata 		wake_up(&ud->eh_waitq);
11496c27377SValentina Manea 	}
11596c27377SValentina Manea }
11696c27377SValentina Manea 
11796c27377SValentina Manea int usbip_start_eh(struct usbip_device *ud)
11896c27377SValentina Manea {
11996c27377SValentina Manea 	init_waitqueue_head(&ud->eh_waitq);
12096c27377SValentina Manea 	ud->event = 0;
12196c27377SValentina Manea 	return 0;
12296c27377SValentina Manea }
12396c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_start_eh);
12496c27377SValentina Manea 
12596c27377SValentina Manea void usbip_stop_eh(struct usbip_device *ud)
12696c27377SValentina Manea {
127bb7871adSNobuo Iwata 	unsigned long pending = ud->event & ~USBIP_EH_BYE;
12896c27377SValentina Manea 
129bb7871adSNobuo Iwata 	if (!(ud->event & USBIP_EH_BYE))
130bb7871adSNobuo Iwata 		usbip_dbg_eh("usbip_eh stopping but not removed\n");
131bb7871adSNobuo Iwata 
132bb7871adSNobuo Iwata 	if (pending)
133bb7871adSNobuo Iwata 		usbip_dbg_eh("usbip_eh waiting completion %lx\n", pending);
134bb7871adSNobuo Iwata 
135bb7871adSNobuo Iwata 	wait_event_interruptible(ud->eh_waitq, !(ud->event & ~USBIP_EH_BYE));
136bb7871adSNobuo Iwata 	usbip_dbg_eh("usbip_eh has stopped\n");
13796c27377SValentina Manea }
13896c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_stop_eh);
13996c27377SValentina Manea 
140bb7871adSNobuo Iwata #define WORK_QUEUE_NAME "usbip_event"
141bb7871adSNobuo Iwata 
142bb7871adSNobuo Iwata static struct workqueue_struct *usbip_queue;
143bb7871adSNobuo Iwata static DECLARE_WORK(usbip_work, event_handler);
144bb7871adSNobuo Iwata 
145bb7871adSNobuo Iwata int usbip_init_eh(void)
146bb7871adSNobuo Iwata {
147bb7871adSNobuo Iwata 	usbip_queue = create_singlethread_workqueue(WORK_QUEUE_NAME);
148bb7871adSNobuo Iwata 	if (usbip_queue == NULL) {
149bb7871adSNobuo Iwata 		pr_err("failed to create usbip_event\n");
150bb7871adSNobuo Iwata 		return -ENOMEM;
151bb7871adSNobuo Iwata 	}
152bb7871adSNobuo Iwata 	return 0;
153bb7871adSNobuo Iwata }
154bb7871adSNobuo Iwata 
155bb7871adSNobuo Iwata void usbip_finish_eh(void)
156bb7871adSNobuo Iwata {
157bb7871adSNobuo Iwata 	flush_workqueue(usbip_queue);
158bb7871adSNobuo Iwata 	destroy_workqueue(usbip_queue);
159bb7871adSNobuo Iwata 	usbip_queue = NULL;
160bb7871adSNobuo Iwata }
161bb7871adSNobuo Iwata 
16296c27377SValentina Manea void usbip_event_add(struct usbip_device *ud, unsigned long event)
16396c27377SValentina Manea {
164bb7871adSNobuo Iwata 	struct usbip_event *ue;
16596c27377SValentina Manea 	unsigned long flags;
16696c27377SValentina Manea 
167bb7871adSNobuo Iwata 	if (ud->event & USBIP_EH_BYE)
168bb7871adSNobuo Iwata 		return;
169bb7871adSNobuo Iwata 
170bb7871adSNobuo Iwata 	set_event(ud, event);
171bb7871adSNobuo Iwata 
172bb7871adSNobuo Iwata 	spin_lock_irqsave(&event_lock, flags);
173bb7871adSNobuo Iwata 
174bb7871adSNobuo Iwata 	list_for_each_entry_reverse(ue, &event_list, node) {
175bb7871adSNobuo Iwata 		if (ue->ud == ud)
176bb7871adSNobuo Iwata 			goto out;
177bb7871adSNobuo Iwata 	}
178bb7871adSNobuo Iwata 
179bb7871adSNobuo Iwata 	ue = kmalloc(sizeof(struct usbip_event), GFP_ATOMIC);
180bb7871adSNobuo Iwata 	if (ue == NULL)
181bb7871adSNobuo Iwata 		goto out;
182bb7871adSNobuo Iwata 
183bb7871adSNobuo Iwata 	ue->ud = ud;
184bb7871adSNobuo Iwata 
185bb7871adSNobuo Iwata 	list_add_tail(&ue->node, &event_list);
186bb7871adSNobuo Iwata 	queue_work(usbip_queue, &usbip_work);
187bb7871adSNobuo Iwata 
188bb7871adSNobuo Iwata out:
189bb7871adSNobuo Iwata 	spin_unlock_irqrestore(&event_lock, flags);
19096c27377SValentina Manea }
19196c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_event_add);
19296c27377SValentina Manea 
19396c27377SValentina Manea int usbip_event_happened(struct usbip_device *ud)
19496c27377SValentina Manea {
19596c27377SValentina Manea 	int happened = 0;
19621619792SAndrew Goodbody 	unsigned long flags;
19796c27377SValentina Manea 
19821619792SAndrew Goodbody 	spin_lock_irqsave(&ud->lock, flags);
19996c27377SValentina Manea 	if (ud->event != 0)
20096c27377SValentina Manea 		happened = 1;
20121619792SAndrew Goodbody 	spin_unlock_irqrestore(&ud->lock, flags);
20296c27377SValentina Manea 
20396c27377SValentina Manea 	return happened;
20496c27377SValentina Manea }
20596c27377SValentina Manea EXPORT_SYMBOL_GPL(usbip_event_happened);
206bb7871adSNobuo Iwata 
207bb7871adSNobuo Iwata int usbip_in_eh(struct task_struct *task)
208bb7871adSNobuo Iwata {
209bb7871adSNobuo Iwata 	if (task == worker_context)
210bb7871adSNobuo Iwata 		return 1;
211bb7871adSNobuo Iwata 
212bb7871adSNobuo Iwata 	return 0;
213bb7871adSNobuo Iwata }
214bb7871adSNobuo Iwata EXPORT_SYMBOL_GPL(usbip_in_eh);
215