diff options
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_arb.c | 3 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/module.c | 108 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/module.h | 2 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/pci.c | 56 |
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 | */ | ||
649 | int 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 | |||
643 | static void gk20a_pm_shutdown(struct platform_device *pdev) | 685 | static 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 | ||
982 | static int __exit gk20a_remove(struct platform_device *pdev) | 1001 | int 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 | ||
1044 | static 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 | |||
1037 | static struct platform_driver gk20a_driver = { | 1061 | static 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; | |||
19 | int gk20a_pm_finalize_poweron(struct device *dev); | 19 | int gk20a_pm_finalize_poweron(struct device *dev); |
20 | void gk20a_remove_support(struct gk20a *g); | 20 | void gk20a_remove_support(struct gk20a *g); |
21 | void gk20a_driver_start_unload(struct gk20a *g); | 21 | void gk20a_driver_start_unload(struct gk20a *g); |
22 | int nvgpu_quiesce(struct gk20a *g); | ||
23 | int nvgpu_remove(struct device *dev, struct class *class); | ||
22 | 24 | ||
23 | extern struct class nvgpu_class; | 25 | extern 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 | ||
514 | static void nvgpu_pci_remove(struct pci_dev *pdev) | 514 | static 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 | } |