aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/misc/ftdi-elan.c
diff options
context:
space:
mode:
authorBhaktipriya Shridhar <bhaktipriya96@gmail.com>2016-07-26 01:17:20 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-08-09 09:49:01 -0400
commitc936f45fc25fd53c1517571aa379e07bca1f28ed (patch)
tree6202eb1870599813a36f090cf098614fdc9ea260 /drivers/usb/misc/ftdi-elan.c
parent6a0bb4348bb4b6cce1bb06ac8fa38fc4fb0d9088 (diff)
usb: ftdi-elan: Remove deprecated create_singlethread_workqueue
The status workqueue is involved in initializing the Uxxx and polling the Uxxx until a supported PCMCIA CardBus device is detected. It then starts the command and respond workqueues and then loads the module that handles the device, after which it just polls the Uxxx looking for card ejects. The command and respond workqueues are involved in implementing a command sequencer for communicating with the firmware on the other side of the FTDI chip in the Uxxx. These workqueues have only a single work item each and hence they do not require ordering. Also, none of the above workqueues are being used on a memory recliam path. Hence, the singlethreaded workqueues have been replaced with the use of system_wq. System workqueues have been able to handle high level of concurrency for a long time now and hence it's not required to have a singlethreaded workqueue just to gain concurrency. Unlike a dedicated per-cpu workqueue created with create_singlethread_workqueue(), system_wq allows multiple work items to overlap executions even on the same CPU; however, a per-cpu workqueue doesn't have any CPU locality or global ordering guarantee unless the target CPU is explicitly specified and thus the increase of local concurrency shouldn't make any difference. The work items have been sync cancelled because they are self-requeueing and need to wait for the in-flight work item to finish before proceeding with destruction. Hence, they have been sync cancelled in ftdi_status_cancel_work(), ftdi_command_cancel_work() and ftdi_response_cancel_work(). These functions are called in ftdi_elan_exit() to ensure that there are no pending work items while disconnecting the driver. Signed-off-by: Bhaktipriya Shridhar <bhaktipriya96@gmail.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/misc/ftdi-elan.c')
-rw-r--r--drivers/usb/misc/ftdi-elan.c53
1 files changed, 10 insertions, 43 deletions
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 52c27cab78c3..59031dc21eab 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -61,9 +61,6 @@ module_param(distrust_firmware, bool, 0);
61MODULE_PARM_DESC(distrust_firmware, 61MODULE_PARM_DESC(distrust_firmware,
62 "true to distrust firmware power/overcurrent setup"); 62 "true to distrust firmware power/overcurrent setup");
63extern struct platform_driver u132_platform_driver; 63extern struct platform_driver u132_platform_driver;
64static struct workqueue_struct *status_queue;
65static struct workqueue_struct *command_queue;
66static struct workqueue_struct *respond_queue;
67/* 64/*
68 * ftdi_module_lock exists to protect access to global variables 65 * ftdi_module_lock exists to protect access to global variables
69 * 66 *
@@ -228,56 +225,56 @@ static void ftdi_elan_init_kref(struct usb_ftdi *ftdi)
228 225
229static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) 226static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
230{ 227{
231 if (!queue_delayed_work(status_queue, &ftdi->status_work, delta)) 228 if (!schedule_delayed_work(&ftdi->status_work, delta))
232 kref_put(&ftdi->kref, ftdi_elan_delete); 229 kref_put(&ftdi->kref, ftdi_elan_delete);
233} 230}
234 231
235static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) 232static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
236{ 233{
237 if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) 234 if (schedule_delayed_work(&ftdi->status_work, delta))
238 kref_get(&ftdi->kref); 235 kref_get(&ftdi->kref);
239} 236}
240 237
241static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) 238static void ftdi_status_cancel_work(struct usb_ftdi *ftdi)
242{ 239{
243 if (cancel_delayed_work(&ftdi->status_work)) 240 if (cancel_delayed_work_sync(&ftdi->status_work))
244 kref_put(&ftdi->kref, ftdi_elan_delete); 241 kref_put(&ftdi->kref, ftdi_elan_delete);
245} 242}
246 243
247static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) 244static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
248{ 245{
249 if (!queue_delayed_work(command_queue, &ftdi->command_work, delta)) 246 if (!schedule_delayed_work(&ftdi->command_work, delta))
250 kref_put(&ftdi->kref, ftdi_elan_delete); 247 kref_put(&ftdi->kref, ftdi_elan_delete);
251} 248}
252 249
253static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) 250static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
254{ 251{
255 if (queue_delayed_work(command_queue, &ftdi->command_work, delta)) 252 if (schedule_delayed_work(&ftdi->command_work, delta))
256 kref_get(&ftdi->kref); 253 kref_get(&ftdi->kref);
257} 254}
258 255
259static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) 256static void ftdi_command_cancel_work(struct usb_ftdi *ftdi)
260{ 257{
261 if (cancel_delayed_work(&ftdi->command_work)) 258 if (cancel_delayed_work_sync(&ftdi->command_work))
262 kref_put(&ftdi->kref, ftdi_elan_delete); 259 kref_put(&ftdi->kref, ftdi_elan_delete);
263} 260}
264 261
265static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, 262static void ftdi_response_requeue_work(struct usb_ftdi *ftdi,
266 unsigned int delta) 263 unsigned int delta)
267{ 264{
268 if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) 265 if (!schedule_delayed_work(&ftdi->respond_work, delta))
269 kref_put(&ftdi->kref, ftdi_elan_delete); 266 kref_put(&ftdi->kref, ftdi_elan_delete);
270} 267}
271 268
272static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) 269static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
273{ 270{
274 if (queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) 271 if (schedule_delayed_work(&ftdi->respond_work, delta))
275 kref_get(&ftdi->kref); 272 kref_get(&ftdi->kref);
276} 273}
277 274
278static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) 275static void ftdi_response_cancel_work(struct usb_ftdi *ftdi)
279{ 276{
280 if (cancel_delayed_work(&ftdi->respond_work)) 277 if (cancel_delayed_work_sync(&ftdi->respond_work))
281 kref_put(&ftdi->kref, ftdi_elan_delete); 278 kref_put(&ftdi->kref, ftdi_elan_delete);
282} 279}
283 280
@@ -2823,9 +2820,6 @@ static void ftdi_elan_disconnect(struct usb_interface *interface)
2823 ftdi->initialized = 0; 2820 ftdi->initialized = 0;
2824 ftdi->registered = 0; 2821 ftdi->registered = 0;
2825 } 2822 }
2826 flush_workqueue(status_queue);
2827 flush_workqueue(command_queue);
2828 flush_workqueue(respond_queue);
2829 ftdi->disconnected += 1; 2823 ftdi->disconnected += 1;
2830 usb_set_intfdata(interface, NULL); 2824 usb_set_intfdata(interface, NULL);
2831 dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n"); 2825 dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n");
@@ -2845,31 +2839,12 @@ static int __init ftdi_elan_init(void)
2845 pr_info("driver %s\n", ftdi_elan_driver.name); 2839 pr_info("driver %s\n", ftdi_elan_driver.name);
2846 mutex_init(&ftdi_module_lock); 2840 mutex_init(&ftdi_module_lock);
2847 INIT_LIST_HEAD(&ftdi_static_list); 2841 INIT_LIST_HEAD(&ftdi_static_list);
2848 status_queue = create_singlethread_workqueue("ftdi-status-control");
2849 if (!status_queue)
2850 goto err_status_queue;
2851 command_queue = create_singlethread_workqueue("ftdi-command-engine");
2852 if (!command_queue)
2853 goto err_command_queue;
2854 respond_queue = create_singlethread_workqueue("ftdi-respond-engine");
2855 if (!respond_queue)
2856 goto err_respond_queue;
2857 result = usb_register(&ftdi_elan_driver); 2842 result = usb_register(&ftdi_elan_driver);
2858 if (result) { 2843 if (result) {
2859 destroy_workqueue(status_queue);
2860 destroy_workqueue(command_queue);
2861 destroy_workqueue(respond_queue);
2862 pr_err("usb_register failed. Error number %d\n", result); 2844 pr_err("usb_register failed. Error number %d\n", result);
2863 } 2845 }
2864 return result; 2846 return result;
2865 2847
2866err_respond_queue:
2867 destroy_workqueue(command_queue);
2868err_command_queue:
2869 destroy_workqueue(status_queue);
2870err_status_queue:
2871 pr_err("%s couldn't create workqueue\n", ftdi_elan_driver.name);
2872 return -ENOMEM;
2873} 2848}
2874 2849
2875static void __exit ftdi_elan_exit(void) 2850static void __exit ftdi_elan_exit(void)
@@ -2882,15 +2857,7 @@ static void __exit ftdi_elan_exit(void)
2882 ftdi_status_cancel_work(ftdi); 2857 ftdi_status_cancel_work(ftdi);
2883 ftdi_command_cancel_work(ftdi); 2858 ftdi_command_cancel_work(ftdi);
2884 ftdi_response_cancel_work(ftdi); 2859 ftdi_response_cancel_work(ftdi);
2885 } flush_workqueue(status_queue); 2860 }
2886 destroy_workqueue(status_queue);
2887 status_queue = NULL;
2888 flush_workqueue(command_queue);
2889 destroy_workqueue(command_queue);
2890 command_queue = NULL;
2891 flush_workqueue(respond_queue);
2892 destroy_workqueue(respond_queue);
2893 respond_queue = NULL;
2894} 2861}
2895 2862
2896 2863