summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
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
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')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.c3
-rw-r--r--drivers/gpu/nvgpu/common/linux/module.c108
-rw-r--r--drivers/gpu/nvgpu/common/linux/module.h2
-rw-r--r--drivers/gpu/nvgpu/common/linux/pci.c56
4 files changed, 88 insertions, 81 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.c b/drivers/gpu/nvgpu/clk/clk_arb.c
index 0204627b..4f09da74 100644
--- a/drivers/gpu/nvgpu/clk/clk_arb.c
+++ b/drivers/gpu/nvgpu/clk/clk_arb.c
@@ -489,9 +489,8 @@ void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g)
489 nvgpu_kfree(g, arb->vf_table_pool[index].gpc2clk_points); 489 nvgpu_kfree(g, arb->vf_table_pool[index].gpc2clk_points);
490 nvgpu_kfree(g, arb->vf_table_pool[index].mclk_points); 490 nvgpu_kfree(g, arb->vf_table_pool[index].mclk_points);
491 } 491 }
492 nvgpu_mutex_destroy(&g->clk_arb->pstate_lock);
492 } 493 }
493
494 nvgpu_mutex_destroy(&g->clk_arb->pstate_lock);
495 nvgpu_kfree(g, g->clk_arb); 494 nvgpu_kfree(g, g->clk_arb);
496 g->clk_arb = NULL; 495 g->clk_arb = NULL;
497} 496}
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),
diff --git a/drivers/gpu/nvgpu/common/linux/module.h b/drivers/gpu/nvgpu/common/linux/module.h
index cfbbc0c7..def98288 100644
--- a/drivers/gpu/nvgpu/common/linux/module.h
+++ b/drivers/gpu/nvgpu/common/linux/module.h
@@ -19,6 +19,8 @@ struct device;
19int gk20a_pm_finalize_poweron(struct device *dev); 19int gk20a_pm_finalize_poweron(struct device *dev);
20void gk20a_remove_support(struct gk20a *g); 20void gk20a_remove_support(struct gk20a *g);
21void gk20a_driver_start_unload(struct gk20a *g); 21void gk20a_driver_start_unload(struct gk20a *g);
22int nvgpu_quiesce(struct gk20a *g);
23int nvgpu_remove(struct device *dev, struct class *class);
22 24
23extern struct class nvgpu_class; 25extern struct class nvgpu_class;
24 26
diff --git a/drivers/gpu/nvgpu/common/linux/pci.c b/drivers/gpu/nvgpu/common/linux/pci.c
index 4ea86e7f..f1d12367 100644
--- a/drivers/gpu/nvgpu/common/linux/pci.c
+++ b/drivers/gpu/nvgpu/common/linux/pci.c
@@ -513,52 +513,34 @@ static int nvgpu_pci_probe(struct pci_dev *pdev,
513 513
514static void nvgpu_pci_remove(struct pci_dev *pdev) 514static void nvgpu_pci_remove(struct pci_dev *pdev)
515{ 515{
516 struct gk20a_platform *platform = gk20a_get_platform(&pdev->dev);
517 struct gk20a *g = get_gk20a(&pdev->dev); 516 struct gk20a *g = get_gk20a(&pdev->dev);
518 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); 517 struct device *dev = dev_from_gk20a(g);
518 int err;
519 519
520 gk20a_dbg(gpu_dbg_shutdown, "Removing nvgpu driver!\n"); 520 /* no support yet for unbind if DGPU is in VGPU mode */
521 if (gk20a_gpu_is_virtual(dev))
522 return;
521 523
522 if (g->irqs_enabled) 524 /* only idle the GPU if the GPU is powered on */
523 disable_irq(g->irq_stall); 525 if (g->power_on) {
526 gk20a_driver_start_unload(g);
527 err = nvgpu_quiesce(g);
528 /* TODO: handle failure to idle */
529 WARN(err, "gpu failed to idle during driver removal");
530 }
524 531
525 devm_free_irq(&pdev->dev, g->irq_stall, g); 532 nvgpu_remove(dev, &nvgpu_pci_class);
526 533
527#if defined(CONFIG_PCI_MSI) 534#if defined(CONFIG_PCI_MSI)
528 if (g->msi_enabled) { 535 if (g->msi_enabled)
529 pci_disable_msi(pdev); 536 pci_disable_msi(pdev);
530 g->msi_enabled = false; 537 else {
538 /* IRQ does not need to be enabled in MSI as the line is not
539 * shared
540 */
541 enable_irq(g->irq_stall);
531 } 542 }
532#endif 543#endif
533 gk20a_dbg(gpu_dbg_shutdown, "IRQs disabled.\n");
534
535 /*
536 * Wait for the driver to finish up all the IOCTLs it's working on
537 * before cleaning up the driver's data structures.
538 */
539 gk20a_driver_start_unload(g);
540 gk20a_dbg(gpu_dbg_shutdown, "Driver idle.\n");
541
542#ifdef CONFIG_ARCH_TEGRA_18x_SOC
543 nvgpu_clk_arb_cleanup_arbiter(g);
544#endif
545
546 gk20a_user_deinit(dev_from_gk20a(g), &nvgpu_pci_class);
547 gk20a_dbg(gpu_dbg_shutdown, "User de-init done.\b");
548
549#ifdef CONFIG_DEBUG_FS
550 debugfs_remove_recursive(l->debugfs);
551 debugfs_remove_recursive(l->debugfs_alias);
552#endif
553
554 nvgpu_remove_sysfs(dev_from_gk20a(g));
555
556 if (platform->remove)
557 platform->remove(dev_from_gk20a(g));
558 gk20a_dbg(gpu_dbg_shutdown, "Platform remove done.\b");
559
560 enable_irq(g->irq_stall);
561
562 gk20a_get_platform(&pdev->dev)->g = NULL; 544 gk20a_get_platform(&pdev->dev)->g = NULL;
563 gk20a_put(g); 545 gk20a_put(g);
564} 546}