aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2016-06-30 04:51:44 -0400
committerAlexander Shishkin <alexander.shishkin@linux.intel.com>2016-07-14 06:02:39 -0400
commita36aa80f3cb2540fb1dbad6240852de4365a2e82 (patch)
tree193a9f67ab7426ed0e2fa650445ea2cd4f997a3a
parentaf8c34ce6ae32addda3788d54a7e340cad22516b (diff)
intel_th: Fix a deadlock in modprobing
Driver initialization tries to request a hub (GTH) driver module from its probe callback, resulting in a deadlock. This patch solves the problem by adding a deferred work for requesting the hub module. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: <stable@vger.kernel.org> # 4.4.x-
-rw-r--r--drivers/hwtracing/intel_th/core.c35
-rw-r--r--drivers/hwtracing/intel_th/intel_th.h3
2 files changed, 37 insertions, 1 deletions
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 1be543e8e42f..0b112ae689bf 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -465,6 +465,38 @@ static struct intel_th_subdevice {
465 }, 465 },
466}; 466};
467 467
468#ifdef CONFIG_MODULES
469static void __intel_th_request_hub_module(struct work_struct *work)
470{
471 struct intel_th *th = container_of(work, struct intel_th,
472 request_module_work);
473
474 request_module("intel_th_%s", th->hub->name);
475}
476
477static int intel_th_request_hub_module(struct intel_th *th)
478{
479 INIT_WORK(&th->request_module_work, __intel_th_request_hub_module);
480 schedule_work(&th->request_module_work);
481
482 return 0;
483}
484
485static void intel_th_request_hub_module_flush(struct intel_th *th)
486{
487 flush_work(&th->request_module_work);
488}
489#else
490static inline int intel_th_request_hub_module(struct intel_th *th)
491{
492 return -EINVAL;
493}
494
495static inline void intel_th_request_hub_module_flush(struct intel_th *th)
496{
497}
498#endif /* CONFIG_MODULES */
499
468static int intel_th_populate(struct intel_th *th, struct resource *devres, 500static int intel_th_populate(struct intel_th *th, struct resource *devres,
469 unsigned int ndevres, int irq) 501 unsigned int ndevres, int irq)
470{ 502{
@@ -535,7 +567,7 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres,
535 /* need switch driver to be loaded to enumerate the rest */ 567 /* need switch driver to be loaded to enumerate the rest */
536 if (subdev->type == INTEL_TH_SWITCH && !req) { 568 if (subdev->type == INTEL_TH_SWITCH && !req) {
537 th->hub = thdev; 569 th->hub = thdev;
538 err = request_module("intel_th_%s", subdev->name); 570 err = intel_th_request_hub_module(th);
539 if (!err) 571 if (!err)
540 req++; 572 req++;
541 } 573 }
@@ -652,6 +684,7 @@ void intel_th_free(struct intel_th *th)
652{ 684{
653 int i; 685 int i;
654 686
687 intel_th_request_hub_module_flush(th);
655 for (i = 0; i < TH_SUBDEVICE_MAX; i++) 688 for (i = 0; i < TH_SUBDEVICE_MAX; i++)
656 if (th->thdev[i] != th->hub) 689 if (th->thdev[i] != th->hub)
657 intel_th_device_remove(th->thdev[i]); 690 intel_th_device_remove(th->thdev[i]);
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index 0df22e30673d..04828482600b 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -205,6 +205,9 @@ struct intel_th {
205 205
206 int id; 206 int id;
207 int major; 207 int major;
208#ifdef CONFIG_MODULES
209 struct work_struct request_module_work;
210#endif /* CONFIG_MODULES */
208#ifdef CONFIG_INTEL_TH_DEBUG 211#ifdef CONFIG_INTEL_TH_DEBUG
209 struct dentry *dbg; 212 struct dentry *dbg;
210#endif 213#endif