summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/module.c
diff options
context:
space:
mode:
authorDavid Nieto <dmartineznie@nvidia.com>2017-09-07 19:12:44 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-09-15 14:25:35 -0400
commitef6ea3475cac013c174905ab4f7f187700ae2a33 (patch)
tree45b5c0c7c6990a317d401fa6e44145fea0e047c8 /drivers/gpu/nvgpu/common/linux/module.c
parent980bf96bf21868e9b1fd8c1ef68da534e97ccbb5 (diff)
gpu: nvgpu: Unify remove/shutdown codepaths
The following changes are part of the porting of the bind/unbind functionality. These changes reuse the shutdown codepaths in iGPU and dGPU and fix a locking issue with in gk20a_busy() where the usage count can lead to a deadlock during the driver shutdown. It fixes a racing condition with the gr/mm code by invalidating the sw ready flag while holding the busy lock JIRA: EVLR-1739 Change-Id: I62ce47378436b21f447f4cd93388759ed3f9bad1 Signed-off-by: David Nieto <dmartineznie@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1554959 Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com> Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/module.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/module.c108
1 files changed, 66 insertions, 42 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/module.c b/drivers/gpu/nvgpu/common/linux/module.c
index 509930c7..46b89ad0 100644
--- a/drivers/gpu/nvgpu/common/linux/module.c
+++ b/drivers/gpu/nvgpu/common/linux/module.c
@@ -640,6 +640,48 @@ static int gk20a_pm_unrailgate(struct device *dev)
640 return ret; 640 return ret;
641} 641}
642 642
643/*
644 * Idle the GPU in preparation of shutdown/remove.
645 * gk20a_driver_start_unload() does not idle the GPU, but instead changes the SW
646 * state to prevent further activity on the driver SW side.
647 * On driver removal quiesce() should be called after start_unload()
648 */
649int nvgpu_quiesce(struct gk20a *g)
650{
651 int err;
652 struct device *dev = dev_from_gk20a(g);
653
654 err = gk20a_wait_for_idle(g);
655 if (err) {
656 nvgpu_err(g, "failed to idle GPU, err=%d", err);
657 return err;
658 }
659
660 err = gk20a_fifo_disable_all_engine_activity(g, true);
661 if (err) {
662 nvgpu_err(g, "failed to disable engine activity, err=%d",
663 err);
664 return err;
665 }
666
667 err = gk20a_fifo_wait_engine_idle(g);
668 if (err) {
669 nvgpu_err(g, "failed to idle engines, err=%d",
670 err);
671 return err;
672 }
673
674 if (gk20a_gpu_is_virtual(dev))
675 err = vgpu_pm_prepare_poweroff(dev);
676 else
677 err = gk20a_pm_prepare_poweroff(dev);
678
679 if (err)
680 nvgpu_err(g, "failed to prepare for poweroff, err=%d",
681 err);
682 return err;
683}
684
643static void gk20a_pm_shutdown(struct platform_device *pdev) 685static void gk20a_pm_shutdown(struct platform_device *pdev)
644{ 686{
645 struct gk20a_platform *platform = platform_get_drvdata(pdev); 687 struct gk20a_platform *platform = platform_get_drvdata(pdev);
@@ -668,35 +710,9 @@ static void gk20a_pm_shutdown(struct platform_device *pdev)
668 /* Prevent more requests by disabling Runtime PM */ 710 /* Prevent more requests by disabling Runtime PM */
669 __pm_runtime_disable(&pdev->dev, false); 711 __pm_runtime_disable(&pdev->dev, false);
670 712
671 err = gk20a_wait_for_idle(g); 713 err = nvgpu_quiesce(g);
672 if (err) { 714 if (err)
673 nvgpu_err(g, "failed to idle GPU, err=%d", err);
674 goto finish;
675 }
676
677 err = gk20a_fifo_disable_all_engine_activity(g, true);
678 if (err) {
679 nvgpu_err(g, "failed to disable engine activity, err=%d",
680 err);
681 goto finish;
682 }
683
684 err = gk20a_fifo_wait_engine_idle(g);
685 if (err) {
686 nvgpu_err(g, "failed to idle engines, err=%d",
687 err);
688 goto finish;
689 }
690
691 if (gk20a_gpu_is_virtual(&pdev->dev))
692 err = vgpu_pm_prepare_poweroff(&pdev->dev);
693 else
694 err = gk20a_pm_prepare_poweroff(&pdev->dev);
695 if (err) {
696 nvgpu_err(g, "failed to prepare for poweroff, err=%d",
697 err);
698 goto finish; 715 goto finish;
699 }
700 716
701 err = gk20a_pm_railgate(&pdev->dev); 717 err = gk20a_pm_railgate(&pdev->dev);
702 if (err) 718 if (err)
@@ -854,6 +870,9 @@ void gk20a_driver_start_unload(struct gk20a *g)
854 870
855 down_write(&g->busy_lock); 871 down_write(&g->busy_lock);
856 __nvgpu_set_enabled(g, NVGPU_DRIVER_IS_DYING, true); 872 __nvgpu_set_enabled(g, NVGPU_DRIVER_IS_DYING, true);
873 /* GR SW ready needs to be invalidated at this time with the busy lock
874 * held to prevent a racing condition on the gr/mm code */
875 g->gr.sw_ready = false;
857 up_write(&g->busy_lock); 876 up_write(&g->busy_lock);
858 877
859 if (g->is_virtual) 878 if (g->is_virtual)
@@ -979,18 +998,14 @@ static int gk20a_probe(struct platform_device *dev)
979 return 0; 998 return 0;
980} 999}
981 1000
982static int __exit gk20a_remove(struct platform_device *pdev) 1001int nvgpu_remove(struct device *dev, struct class *class)
983{ 1002{
984 struct device *dev = &pdev->dev;
985 struct gk20a *g = get_gk20a(dev); 1003 struct gk20a *g = get_gk20a(dev);
986 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); 1004 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
987 struct gk20a_platform *platform = gk20a_get_platform(dev); 1005 struct gk20a_platform *platform = gk20a_get_platform(dev);
988 1006
989 gk20a_dbg_fn(""); 1007 gk20a_dbg_fn("");
990 1008
991 if (gk20a_gpu_is_virtual(dev))
992 return vgpu_remove(pdev);
993
994 if (platform->has_cde) 1009 if (platform->has_cde)
995 gk20a_cde_destroy(l); 1010 gk20a_cde_destroy(l);
996 1011
@@ -1001,16 +1016,11 @@ static int __exit gk20a_remove(struct platform_device *pdev)
1001 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ)) 1016 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ))
1002 gk20a_scale_exit(dev); 1017 gk20a_scale_exit(dev);
1003 1018
1004 if (g->remove_support)
1005 g->remove_support(g);
1006
1007 gk20a_ce_destroy(g);
1008
1009#ifdef CONFIG_ARCH_TEGRA_18x_SOC 1019#ifdef CONFIG_ARCH_TEGRA_18x_SOC
1010 nvgpu_clk_arb_cleanup_arbiter(g); 1020 nvgpu_clk_arb_cleanup_arbiter(g);
1011#endif 1021#endif
1012 1022
1013 gk20a_user_deinit(dev, &nvgpu_class); 1023 gk20a_user_deinit(dev, class);
1014 1024
1015 gk20a_debug_deinit(g); 1025 gk20a_debug_deinit(g);
1016 1026
@@ -1026,14 +1036,28 @@ static int __exit gk20a_remove(struct platform_device *pdev)
1026 if (platform->remove) 1036 if (platform->remove)
1027 platform->remove(dev); 1037 platform->remove(dev);
1028 1038
1029 set_gk20a(pdev, NULL);
1030 gk20a_put(g);
1031
1032 gk20a_dbg_fn("removed"); 1039 gk20a_dbg_fn("removed");
1033 1040
1034 return 0; 1041 return 0;
1035} 1042}
1036 1043
1044static int __exit gk20a_remove(struct platform_device *pdev)
1045{
1046 int err;
1047 struct device *dev = &pdev->dev;
1048 struct gk20a *g = get_gk20a(dev);
1049
1050 if (gk20a_gpu_is_virtual(dev))
1051 return vgpu_remove(pdev);
1052
1053 err = nvgpu_remove(dev, &nvgpu_class);
1054
1055 set_gk20a(pdev, NULL);
1056 gk20a_put(g);
1057
1058 return err;
1059}
1060
1037static struct platform_driver gk20a_driver = { 1061static struct platform_driver gk20a_driver = {
1038 .probe = gk20a_probe, 1062 .probe = gk20a_probe,
1039 .remove = __exit_p(gk20a_remove), 1063 .remove = __exit_p(gk20a_remove),