diff options
author | Alexander Shishkin <alexander.shishkin@linux.intel.com> | 2016-06-30 04:51:44 -0400 |
---|---|---|
committer | Alexander Shishkin <alexander.shishkin@linux.intel.com> | 2016-07-14 06:02:39 -0400 |
commit | a36aa80f3cb2540fb1dbad6240852de4365a2e82 (patch) | |
tree | 193a9f67ab7426ed0e2fa650445ea2cd4f997a3a | |
parent | af8c34ce6ae32addda3788d54a7e340cad22516b (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.c | 35 | ||||
-rw-r--r-- | drivers/hwtracing/intel_th/intel_th.h | 3 |
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 | ||
469 | static 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 | |||
477 | static 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 | |||
485 | static void intel_th_request_hub_module_flush(struct intel_th *th) | ||
486 | { | ||
487 | flush_work(&th->request_module_work); | ||
488 | } | ||
489 | #else | ||
490 | static inline int intel_th_request_hub_module(struct intel_th *th) | ||
491 | { | ||
492 | return -EINVAL; | ||
493 | } | ||
494 | |||
495 | static inline void intel_th_request_hub_module_flush(struct intel_th *th) | ||
496 | { | ||
497 | } | ||
498 | #endif /* CONFIG_MODULES */ | ||
499 | |||
468 | static int intel_th_populate(struct intel_th *th, struct resource *devres, | 500 | static 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 |