diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu
index 658f8b7f4..983df2427 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu
@@ -23,6 +23,7 @@ endif
obj-$(CONFIG_GK20A) := nvgpu.o
nvgpu-y := \
+ common/linux/module.o \
common/linux/kmem.o \
common/linux/timers.o \
common/linux/ioctl.o \
@@ -34,13 +35,13 @@ nvgpu-y := \
common/linux/nvgpu_mem.o \
common/linux/dma.o \
common/linux/soc.o \
+ common/linux/driver_common.o \
common/mm/nvgpu_allocator.o \
common/mm/bitmap_allocator.o \
common/mm/buddy_allocator.o \
common/mm/page_allocator.o \
common/mm/lockless_allocator.o \
common/pramin.o \
- common/nvgpu_common.o \
common/semaphore.o \
common/as.o \
common/rbtree.o \
@@ -105,7 +106,7 @@ nvgpu-y := \
nvgpu-$(CONFIG_TEGRA_GK20A) += tegra/linux/platform_gk20a_tegra.o
nvgpu-$(CONFIG_SYNC) += gk20a/sync_gk20a.o
-nvgpu-$(CONFIG_GK20A_PCI) += pci.o
+nvgpu-$(CONFIG_GK20A_PCI) += common/linux/pci.o
nvgpu-$(CONFIG_TEGRA_GR_VIRTUALIZATION) += \
gk20a/platform_vgpu_tegra.o \
diff --git a/drivers/gpu/nvgpu/common/nvgpu_common.c b/drivers/gpu/nvgpu/common/linux/driver_common.c
similarity index 96%
rename from drivers/gpu/nvgpu/common/nvgpu_common.c
rename to drivers/gpu/nvgpu/common/linux/driver_common.c
index 0c812d34b..5c96b4e8f 100644
--- a/drivers/gpu/nvgpu/common/nvgpu_common.c
+++ b/drivers/gpu/nvgpu/common/linux/driver_common.c
@@ -24,7 +24,7 @@
#include "gk20a/gk20a_scale.h"
#include "gk20a/gk20a.h"
-#include "gk20a/gr_gk20a.h"
+#include "module.h"
#define EMC3D_DEFAULT_RATIO 750
@@ -124,6 +124,20 @@ static void nvgpu_init_mm_vars(struct gk20a *g)
nvgpu_mutex_init(&g->mm.priv_lock);
}
+static int gk20a_secure_page_alloc(struct device *dev)
+{
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ int err = 0;
+
+ if (platform->secure_page_alloc) {
+ err = platform->secure_page_alloc(dev);
+ if (!err)
+ platform->secure_alloc_ready = true;
+ }
+
+ return err;
+}
+
int nvgpu_probe(struct gk20a *g,
const char *debugfs_symlink,
const char *interface_name,
diff --git a/drivers/gpu/nvgpu/common/linux/module.c b/drivers/gpu/nvgpu/common/linux/module.c
new file mode 100644
index 000000000..2cbf996bd
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/module.c
@@ -0,0 +1,1052 @@
+/*
+ * GK20A Graphics
+ *
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "gk20a/gk20a.h"
+#include "vgpu/vgpu.h"
+#include "gk20a/gk20a_scale.h"
+#include "gk20a/ctxsw_trace_gk20a.h"
+#include "pci.h"
+#include "module.h"
+#ifdef CONFIG_TEGRA_19x_GPU
+#include "nvgpu_gpuid_t19x.h"
+#endif
+
+#define CLASS_NAME "nvidia-gpu"
+/* TODO: Change to e.g. "nvidia-gpu%s" once we have symlinks in place. */
+
+#define GK20A_WAIT_FOR_IDLE_MS 2000
+
+#define CREATE_TRACE_POINTS
+#include
+
+void gk20a_busy_noresume(struct device *dev)
+{
+ pm_runtime_get_noresume(dev);
+}
+
+int gk20a_busy(struct gk20a *g)
+{
+ int ret = 0;
+ struct device *dev;
+
+ if (!g)
+ return -ENODEV;
+
+ atomic_inc(&g->usage_count);
+
+ down_read(&g->busy_lock);
+
+ if (!gk20a_can_busy(g)) {
+ ret = -ENODEV;
+ atomic_dec(&g->usage_count);
+ goto fail;
+ }
+
+ dev = g->dev;
+
+ if (pm_runtime_enabled(dev)) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ atomic_dec(&g->usage_count);
+ goto fail;
+ }
+ } else {
+ if (!g->power_on) {
+ ret = gk20a_gpu_is_virtual(dev) ?
+ vgpu_pm_finalize_poweron(dev)
+ : gk20a_pm_finalize_poweron(dev);
+ if (ret) {
+ atomic_dec(&g->usage_count);
+ goto fail;
+ }
+ }
+ }
+
+ gk20a_scale_notify_busy(dev);
+
+fail:
+ up_read(&g->busy_lock);
+
+ return ret < 0 ? ret : 0;
+}
+
+void gk20a_idle_nosuspend(struct device *dev)
+{
+ pm_runtime_put_noidle(dev);
+}
+
+void gk20a_idle(struct gk20a *g)
+{
+ struct device *dev;
+
+ atomic_dec(&g->usage_count);
+ down_read(&g->busy_lock);
+
+ dev = g->dev;
+
+ if (!(dev && gk20a_can_busy(g)))
+ goto fail;
+
+ if (pm_runtime_enabled(dev)) {
+#ifdef CONFIG_PM
+ if (atomic_read(&g->dev->power.usage_count) == 1)
+ gk20a_scale_notify_idle(dev);
+#endif
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_sync_autosuspend(dev);
+
+ } else {
+ gk20a_scale_notify_idle(dev);
+ }
+fail:
+ up_read(&g->busy_lock);
+}
+
+int gk20a_pm_finalize_poweron(struct device *dev)
+{
+ struct gk20a *g = get_gk20a(dev);
+ struct gk20a_platform *platform = gk20a_get_platform(dev);
+ int err, nice_value;
+
+ gk20a_dbg_fn("");
+
+ if (g->power_on)
+ return 0;
+
+ trace_gk20a_finalize_poweron(dev_name(dev));
+
+ /* Increment platform power refcount */
+ if (platform->busy) {
+ err = platform->busy(dev);
+ if (err < 0) {
+ nvgpu_err(g, "failed to poweron platform dependency");
+ return err;
+ }
+ }
+
+ err = gk20a_restore_registers(g);
+ if (err)
+ return err;
+
+ nice_value = task_nice(current);
+ set_user_nice(current, -20);
+
+ err = gk20a_finalize_poweron(g);
+ set_user_nice(current, nice_value);
+ if (err)
+ goto done;
+
+ trace_gk20a_finalize_poweron_done(dev_name(dev));
+
+ enable_irq(g->irq_stall);
+ if (g->irq_stall != g->irq_nonstall)
+ enable_irq(g->irq_nonstall);
+ g->irqs_enabled = 1;
+
+ gk20a_scale_resume(g->dev);
+
+ if (platform->has_cde)
+ gk20a_init_cde_support(g);
+
+done:
+ if (err)
+ g->power_on = false;
+
+ return err;
+}
+
+static int gk20a_pm_prepare_poweroff(struct device *dev)
+{
+ struct gk20a *g = get_gk20a(dev);
+ int ret = 0;
+ struct gk20a_platform *platform = gk20a_get_platform(dev);
+
+ gk20a_dbg_fn("");
+
+ nvgpu_mutex_acquire(&g->poweroff_lock);
+
+ if (!g->power_on)
+ goto done;
+
+ gk20a_scale_suspend(dev);
+
+ ret = gk20a_prepare_poweroff(g);
+ if (ret)
+ goto error;
+
+ /*
+ * After this point, gk20a interrupts should not get
+ * serviced.
+ */
+ disable_irq(g->irq_stall);
+ if (g->irq_stall != g->irq_nonstall)
+ disable_irq(g->irq_nonstall);
+
+ /*
+ * is_fmodel needs to be in gk20a struct for deferred teardown
+ */
+ g->is_fmodel = platform->is_fmodel;
+
+ /* Decrement platform power refcount */
+ if (platform->idle)
+ platform->idle(dev);
+
+ /* Stop CPU from accessing the GPU registers. */
+ gk20a_lockout_registers(g);
+
+ nvgpu_mutex_release(&g->poweroff_lock);
+ return 0;
+
+error:
+ gk20a_scale_resume(dev);
+done:
+ nvgpu_mutex_release(&g->poweroff_lock);
+
+ return ret;
+}
+
+static struct of_device_id tegra_gk20a_of_match[] = {
+#ifdef CONFIG_TEGRA_GK20A
+ { .compatible = "nvidia,tegra124-gk20a",
+ .data = &gk20a_tegra_platform },
+ { .compatible = "nvidia,tegra210-gm20b",
+ .data = &gm20b_tegra_platform },
+#ifdef CONFIG_ARCH_TEGRA_18x_SOC
+ { .compatible = "nvidia,tegra186-gp10b",
+ .data = &gp10b_tegra_platform },
+#endif
+#ifdef CONFIG_TEGRA_19x_GPU
+ { .compatible = TEGRA_19x_GPU_COMPAT_TEGRA,
+ .data = &t19x_gpu_tegra_platform },
+#endif
+#ifdef CONFIG_TEGRA_GR_VIRTUALIZATION
+ { .compatible = "nvidia,tegra124-gk20a-vgpu",
+ .data = &vgpu_tegra_platform },
+#endif
+#else
+ { .compatible = "nvidia,tegra124-gk20a",
+ .data = &gk20a_generic_platform },
+ { .compatible = "nvidia,tegra210-gm20b",
+ .data = &gk20a_generic_platform },
+#ifdef CONFIG_ARCH_TEGRA_18x_SOC
+ { .compatible = TEGRA_18x_GPU_COMPAT_TEGRA,
+ .data = &gk20a_generic_platform },
+#endif
+
+#endif
+ { .compatible = "nvidia,generic-gk20a",
+ .data = &gk20a_generic_platform },
+ { .compatible = "nvidia,generic-gm20b",
+ .data = &gk20a_generic_platform },
+#ifdef CONFIG_ARCH_TEGRA_18x_SOC
+ { .compatible = "nvidia,generic-gp10b",
+ .data = &gk20a_generic_platform },
+#endif
+ { },
+};
+
+#ifdef CONFIG_PM
+/**
+ * __gk20a_do_idle() - force the GPU to idle and railgate
+ *
+ * In success, this call MUST be balanced by caller with __gk20a_do_unidle()
+ *
+ * Acquires two locks : &g->busy_lock and &platform->railgate_lock
+ * In success, we hold these locks and return
+ * In failure, we release these locks and return
+ */
+int __gk20a_do_idle(struct device *dev, bool force_reset)
+{
+ struct gk20a *g = get_gk20a(dev);
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ struct nvgpu_timeout timeout;
+ int ref_cnt;
+ int target_ref_cnt = 0;
+ bool is_railgated;
+ int err = 0;
+
+ /* acquire busy lock to block other busy() calls */
+ down_write(&g->busy_lock);
+
+ /* acquire railgate lock to prevent unrailgate in midst of do_idle() */
+ nvgpu_mutex_acquire(&platform->railgate_lock);
+
+ /* check if it is already railgated ? */
+ if (platform->is_railgated(dev))
+ return 0;
+
+ /*
+ * release railgate_lock, prevent suspend by incrementing usage counter,
+ * re-acquire railgate_lock
+ */
+ nvgpu_mutex_release(&platform->railgate_lock);
+ pm_runtime_get_sync(dev);
+
+ /*
+ * One refcount taken in this API
+ * If User disables rail gating, we take one more
+ * extra refcount
+ */
+ if (platform->user_railgate_disabled)
+ target_ref_cnt = 2;
+ else
+ target_ref_cnt = 1;
+ nvgpu_mutex_acquire(&platform->railgate_lock);
+
+ nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS,
+ NVGPU_TIMER_CPU_TIMER);
+
+ /* check and wait until GPU is idle (with a timeout) */
+ do {
+ nvgpu_msleep(1);
+ ref_cnt = atomic_read(&dev->power.usage_count);
+ } while (ref_cnt != target_ref_cnt && !nvgpu_timeout_expired(&timeout));
+
+ if (ref_cnt != target_ref_cnt) {
+ nvgpu_err(g, "failed to idle - refcount %d != 1",
+ ref_cnt);
+ goto fail_drop_usage_count;
+ }
+
+ /* check if global force_reset flag is set */
+ force_reset |= platform->force_reset_in_do_idle;
+
+ nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS,
+ NVGPU_TIMER_CPU_TIMER);
+
+ if (platform->can_railgate && !force_reset) {
+ /*
+ * Case 1 : GPU railgate is supported
+ *
+ * if GPU is now idle, we will have only one ref count,
+ * drop this ref which will rail gate the GPU
+ */
+ pm_runtime_put_sync(dev);
+
+ /* add sufficient delay to allow GPU to rail gate */
+ nvgpu_msleep(platform->railgate_delay);
+
+ /* check in loop if GPU is railgated or not */
+ do {
+ nvgpu_msleep(1);
+ is_railgated = platform->is_railgated(dev);
+ } while (!is_railgated && !nvgpu_timeout_expired(&timeout));
+
+ if (is_railgated) {
+ return 0;
+ } else {
+ nvgpu_err(g, "failed to idle in timeout");
+ goto fail_timeout;
+ }
+ } else {
+ /*
+ * Case 2 : GPU railgate is not supported or we explicitly
+ * do not want to depend on runtime PM
+ *
+ * if GPU is now idle, call prepare_poweroff() to save the
+ * state and then do explicit railgate
+ *
+ * __gk20a_do_unidle() needs to unrailgate, call
+ * finalize_poweron(), and then call pm_runtime_put_sync()
+ * to balance the GPU usage counter
+ */
+
+ /* Save the GPU state */
+ err = gk20a_pm_prepare_poweroff(dev);
+ if (err)
+ goto fail_drop_usage_count;
+
+ /* railgate GPU */
+ platform->railgate(dev);
+
+ nvgpu_udelay(10);
+
+ g->forced_reset = true;
+ return 0;
+ }
+
+fail_drop_usage_count:
+ pm_runtime_put_noidle(dev);
+fail_timeout:
+ nvgpu_mutex_release(&platform->railgate_lock);
+ up_write(&g->busy_lock);
+ return -EBUSY;
+}
+
+/**
+ * gk20a_do_idle() - wrap up for __gk20a_do_idle() to be called
+ * from outside of GPU driver
+ *
+ * In success, this call MUST be balanced by caller with gk20a_do_unidle()
+ */
+int gk20a_do_idle(void)
+{
+ struct device_node *node =
+ of_find_matching_node(NULL, tegra_gk20a_of_match);
+ struct platform_device *pdev = of_find_device_by_node(node);
+
+ int ret = __gk20a_do_idle(&pdev->dev, true);
+
+ of_node_put(node);
+
+ return ret;
+}
+
+/**
+ * __gk20a_do_unidle() - unblock all the tasks blocked by __gk20a_do_idle()
+ */
+int __gk20a_do_unidle(struct device *dev)
+{
+ struct gk20a *g = get_gk20a(dev);
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ int err;
+
+ if (g->forced_reset) {
+ /*
+ * If we did a forced-reset/railgate
+ * then unrailgate the GPU here first
+ */
+ platform->unrailgate(dev);
+
+ /* restore the GPU state */
+ err = gk20a_pm_finalize_poweron(dev);
+ if (err)
+ return err;
+
+ /* balance GPU usage counter */
+ pm_runtime_put_sync(dev);
+
+ g->forced_reset = false;
+ }
+
+ /* release the lock and open up all other busy() calls */
+ nvgpu_mutex_release(&platform->railgate_lock);
+ up_write(&g->busy_lock);
+
+ return 0;
+}
+
+/**
+ * gk20a_do_unidle() - wrap up for __gk20a_do_unidle()
+ */
+int gk20a_do_unidle(void)
+{
+ struct device_node *node =
+ of_find_matching_node(NULL, tegra_gk20a_of_match);
+ struct platform_device *pdev = of_find_device_by_node(node);
+
+ int ret = __gk20a_do_unidle(&pdev->dev);
+
+ of_node_put(node);
+
+ return ret;
+}
+#endif
+
+static void __iomem *gk20a_ioremap_resource(struct platform_device *dev, int i,
+ struct resource **out)
+{
+ struct resource *r = platform_get_resource(dev, IORESOURCE_MEM, i);
+
+ if (!r)
+ return NULL;
+ if (out)
+ *out = r;
+ return devm_ioremap_resource(&dev->dev, r);
+}
+
+static irqreturn_t gk20a_intr_isr_stall(int irq, void *dev_id)
+{
+ struct gk20a *g = dev_id;
+
+ return g->ops.mc.isr_stall(g);
+}
+
+static irqreturn_t gk20a_intr_isr_nonstall(int irq, void *dev_id)
+{
+ struct gk20a *g = dev_id;
+
+ return g->ops.mc.isr_nonstall(g);
+}
+
+static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id)
+{
+ struct gk20a *g = dev_id;
+
+ return g->ops.mc.isr_thread_stall(g);
+}
+
+void gk20a_remove_support(struct gk20a *g)
+{
+#ifdef CONFIG_TEGRA_COMMON
+ tegra_unregister_idle_unidle();
+#endif
+ nvgpu_kfree(g, g->dbg_regops_tmp_buf);
+
+ if (g->pmu.remove_support)
+ g->pmu.remove_support(&g->pmu);
+
+ if (g->gr.remove_support)
+ g->gr.remove_support(&g->gr);
+
+ if (g->mm.remove_ce_support)
+ g->mm.remove_ce_support(&g->mm);
+
+ if (g->fifo.remove_support)
+ g->fifo.remove_support(&g->fifo);
+
+ if (g->mm.remove_support)
+ g->mm.remove_support(&g->mm);
+
+ if (g->sim.remove_support)
+ g->sim.remove_support(&g->sim);
+
+ /* free mappings to registers, etc */
+
+ if (g->regs) {
+ iounmap(g->regs);
+ g->regs = NULL;
+ }
+ if (g->bar1) {
+ iounmap(g->bar1);
+ g->bar1 = NULL;
+ }
+}
+
+static int gk20a_init_support(struct platform_device *dev)
+{
+ int err = 0;
+ struct gk20a *g = get_gk20a(&dev->dev);
+
+#ifdef CONFIG_TEGRA_COMMON
+ tegra_register_idle_unidle(gk20a_do_idle, gk20a_do_unidle);
+#endif
+
+ g->regs = gk20a_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM,
+ &g->reg_mem);
+ if (IS_ERR(g->regs)) {
+ nvgpu_err(g, "failed to remap gk20a registers");
+ err = PTR_ERR(g->regs);
+ goto fail;
+ }
+
+ g->bar1 = gk20a_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM,
+ &g->bar1_mem);
+ if (IS_ERR(g->bar1)) {
+ nvgpu_err(g, "failed to remap gk20a bar1");
+ err = PTR_ERR(g->bar1);
+ goto fail;
+ }
+
+ if (nvgpu_platform_is_simulation(g)) {
+ g->sim.g = g;
+ g->sim.regs = gk20a_ioremap_resource(dev,
+ GK20A_SIM_IORESOURCE_MEM,
+ &g->sim.reg_mem);
+ if (IS_ERR(g->sim.regs)) {
+ nvgpu_err(g, "failed to remap gk20a sim regs");
+ err = PTR_ERR(g->sim.regs);
+ goto fail;
+ }
+
+ err = gk20a_init_sim_support(dev);
+ if (err)
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ return err;
+}
+
+static int gk20a_pm_railgate(struct device *dev)
+{
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ int ret = 0;
+#ifdef CONFIG_DEBUG_FS
+ struct gk20a *g = get_gk20a(dev);
+
+ g->pstats.last_rail_gate_start = jiffies;
+
+ if (g->pstats.railgating_cycle_count >= 1)
+ g->pstats.total_rail_ungate_time_ms =
+ g->pstats.total_rail_ungate_time_ms +
+ jiffies_to_msecs(g->pstats.last_rail_gate_start -
+ g->pstats.last_rail_ungate_complete);
+#endif
+
+ if (platform->railgate)
+ ret = platform->railgate(dev);
+
+#ifdef CONFIG_DEBUG_FS
+ g->pstats.last_rail_gate_complete = jiffies;
+#endif
+
+ return ret;
+}
+
+static int gk20a_pm_unrailgate(struct device *dev)
+{
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ int ret = 0;
+ struct gk20a *g = get_gk20a(dev);
+
+#ifdef CONFIG_DEBUG_FS
+ g->pstats.last_rail_ungate_start = jiffies;
+ if (g->pstats.railgating_cycle_count >= 1)
+ g->pstats.total_rail_gate_time_ms =
+ g->pstats.total_rail_gate_time_ms +
+ jiffies_to_msecs(g->pstats.last_rail_ungate_start -
+ g->pstats.last_rail_gate_complete);
+
+ g->pstats.railgating_cycle_count++;
+#endif
+
+ trace_gk20a_pm_unrailgate(dev_name(dev));
+
+ if (platform->unrailgate) {
+ nvgpu_mutex_acquire(&platform->railgate_lock);
+ ret = platform->unrailgate(dev);
+ nvgpu_mutex_release(&platform->railgate_lock);
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ g->pstats.last_rail_ungate_complete = jiffies;
+#endif
+
+ return ret;
+}
+
+static void gk20a_pm_shutdown(struct platform_device *pdev)
+{
+ struct gk20a_platform *platform = platform_get_drvdata(pdev);
+ struct gk20a *g = platform->g;
+ int err;
+
+ nvgpu_info(g, "shutting down");
+
+ /* vgpu has nothing to clean up currently */
+ if (gk20a_gpu_is_virtual(&pdev->dev))
+ return;
+
+ gk20a_driver_start_unload(g);
+
+ /* If GPU is already railgated,
+ * just prevent more requests, and return */
+ if (platform->is_railgated && platform->is_railgated(&pdev->dev)) {
+ __pm_runtime_disable(&pdev->dev, false);
+ nvgpu_info(g, "already railgated, shut down complete");
+ return;
+ }
+
+ /* Prevent more requests by disabling Runtime PM */
+ __pm_runtime_disable(&pdev->dev, false);
+
+ err = gk20a_wait_for_idle(&pdev->dev);
+ if (err) {
+ nvgpu_err(g, "failed to idle GPU, err=%d", err);
+ goto finish;
+ }
+
+ err = gk20a_fifo_disable_all_engine_activity(g, true);
+ if (err) {
+ nvgpu_err(g, "failed to disable engine activity, err=%d",
+ err);
+ goto finish;
+ }
+
+ err = gk20a_fifo_wait_engine_idle(g);
+ if (err) {
+ nvgpu_err(g, "failed to idle engines, err=%d",
+ err);
+ goto finish;
+ }
+
+ if (gk20a_gpu_is_virtual(&pdev->dev))
+ err = vgpu_pm_prepare_poweroff(&pdev->dev);
+ else
+ err = gk20a_pm_prepare_poweroff(&pdev->dev);
+ if (err) {
+ nvgpu_err(g, "failed to prepare for poweroff, err=%d",
+ err);
+ goto finish;
+ }
+
+ err = gk20a_pm_railgate(&pdev->dev);
+ if (err)
+ nvgpu_err(g, "failed to railgate, err=%d", err);
+
+finish:
+ nvgpu_info(g, "shut down complete");
+}
+
+#ifdef CONFIG_PM
+static int gk20a_pm_runtime_resume(struct device *dev)
+{
+ int err = 0;
+
+ err = gk20a_pm_unrailgate(dev);
+ if (err)
+ goto fail;
+
+ err = gk20a_pm_finalize_poweron(dev);
+ if (err)
+ goto fail_poweron;
+
+ return 0;
+
+fail_poweron:
+ gk20a_pm_railgate(dev);
+fail:
+ return err;
+}
+
+static int gk20a_pm_runtime_suspend(struct device *dev)
+{
+ int err = 0;
+
+ err = gk20a_pm_prepare_poweroff(dev);
+ if (err)
+ goto fail;
+
+ err = gk20a_pm_railgate(dev);
+ if (err)
+ goto fail_railgate;
+
+ return 0;
+
+fail_railgate:
+ gk20a_pm_finalize_poweron(dev);
+fail:
+ pm_runtime_mark_last_busy(dev);
+ return err;
+}
+
+static int gk20a_pm_suspend(struct device *dev)
+{
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ struct gk20a *g = get_gk20a(dev);
+ int ret = 0;
+
+ if (platform->user_railgate_disabled)
+ gk20a_idle_nosuspend(dev);
+
+ if (atomic_read(&dev->power.usage_count) > 1) {
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ if (!g->power_on)
+ return 0;
+
+ ret = gk20a_pm_runtime_suspend(dev);
+ if (ret)
+ goto fail;
+
+ if (platform->suspend)
+ platform->suspend(dev);
+
+ g->suspended = true;
+
+ return 0;
+
+fail:
+ if (platform->user_railgate_disabled)
+ gk20a_busy_noresume(dev);
+
+ return ret;
+}
+
+static int gk20a_pm_resume(struct device *dev)
+{
+ struct gk20a *g = get_gk20a(dev);
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (platform->user_railgate_disabled)
+ gk20a_busy_noresume(dev);
+
+ if (!g->suspended)
+ return 0;
+
+ ret = gk20a_pm_runtime_resume(dev);
+
+ g->suspended = false;
+
+ return ret;
+}
+
+static const struct dev_pm_ops gk20a_pm_ops = {
+ .runtime_resume = gk20a_pm_runtime_resume,
+ .runtime_suspend = gk20a_pm_runtime_suspend,
+ .resume = gk20a_pm_resume,
+ .suspend = gk20a_pm_suspend,
+};
+#endif
+
+int gk20a_pm_init(struct device *dev)
+{
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ int err = 0;
+
+ gk20a_dbg_fn("");
+
+ /* Initialise pm runtime */
+ if (platform->railgate_delay) {
+ pm_runtime_set_autosuspend_delay(dev,
+ platform->railgate_delay);
+ pm_runtime_use_autosuspend(dev);
+ }
+
+ if (platform->can_railgate) {
+ pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev))
+ gk20a_pm_unrailgate(dev);
+ else
+ gk20a_pm_railgate(dev);
+ } else {
+ __pm_runtime_disable(dev, false);
+ gk20a_pm_unrailgate(dev);
+ }
+
+ return err;
+}
+
+static inline void set_gk20a(struct platform_device *pdev, struct gk20a *gk20a)
+{
+ gk20a_get_platform(&pdev->dev)->g = gk20a;
+}
+
+static int gk20a_probe(struct platform_device *dev)
+{
+ struct gk20a *gk20a;
+ int err;
+ struct gk20a_platform *platform = NULL;
+
+ if (dev->dev.of_node) {
+ const struct of_device_id *match;
+
+ match = of_match_device(tegra_gk20a_of_match, &dev->dev);
+ if (match)
+ platform = (struct gk20a_platform *)match->data;
+ } else
+ platform = (struct gk20a_platform *)dev->dev.platform_data;
+
+ if (!platform) {
+ dev_err(&dev->dev, "no platform data\n");
+ return -ENODATA;
+ }
+
+ gk20a_dbg_fn("");
+
+ platform_set_drvdata(dev, platform);
+
+ if (gk20a_gpu_is_virtual(&dev->dev))
+ return vgpu_probe(dev);
+
+ gk20a = kzalloc(sizeof(struct gk20a), GFP_KERNEL);
+ if (!gk20a) {
+ dev_err(&dev->dev, "couldn't allocate gk20a support");
+ return -ENOMEM;
+ }
+
+ set_gk20a(dev, gk20a);
+ gk20a->dev = &dev->dev;
+
+ if (nvgpu_platform_is_simulation(gk20a))
+ platform->is_fmodel = true;
+
+ nvgpu_kmem_init(gk20a);
+
+ gk20a->irq_stall = platform_get_irq(dev, 0);
+ gk20a->irq_nonstall = platform_get_irq(dev, 1);
+ if (gk20a->irq_stall < 0 || gk20a->irq_nonstall < 0)
+ return -ENXIO;
+
+ err = devm_request_threaded_irq(&dev->dev,
+ gk20a->irq_stall,
+ gk20a_intr_isr_stall,
+ gk20a_intr_thread_stall,
+ 0, "gk20a_stall", gk20a);
+ if (err) {
+ dev_err(&dev->dev,
+ "failed to request stall intr irq @ %d\n",
+ gk20a->irq_stall);
+ return err;
+ }
+ err = devm_request_irq(&dev->dev,
+ gk20a->irq_nonstall,
+ gk20a_intr_isr_nonstall,
+ 0, "gk20a_nonstall", gk20a);
+ if (err) {
+ dev_err(&dev->dev,
+ "failed to request non-stall intr irq @ %d\n",
+ gk20a->irq_nonstall);
+ return err;
+ }
+ disable_irq(gk20a->irq_stall);
+ if (gk20a->irq_stall != gk20a->irq_nonstall)
+ disable_irq(gk20a->irq_nonstall);
+
+ err = gk20a_init_support(dev);
+ if (err)
+ return err;
+
+#ifdef CONFIG_RESET_CONTROLLER
+ platform->reset_control = devm_reset_control_get(&dev->dev, NULL);
+ if (IS_ERR(platform->reset_control))
+ platform->reset_control = NULL;
+#endif
+
+ err = nvgpu_probe(gk20a, "gpu.0", INTERFACE_NAME, &nvgpu_class);
+ if (err)
+ return err;
+
+ err = gk20a_pm_init(&dev->dev);
+ if (err) {
+ dev_err(&dev->dev, "pm init failed");
+ return err;
+ }
+
+ gk20a->mm.has_physical_mode = !nvgpu_is_hypervisor_mode(gk20a);
+
+ return 0;
+}
+
+static int __exit gk20a_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gk20a *g = get_gk20a(dev);
+ struct gk20a_platform *platform = gk20a_get_platform(dev);
+
+ gk20a_dbg_fn("");
+
+ if (gk20a_gpu_is_virtual(dev))
+ return vgpu_remove(pdev);
+
+ if (platform->has_cde)
+ gk20a_cde_destroy(g);
+
+ gk20a_ctxsw_trace_cleanup(g);
+
+ gk20a_sched_ctrl_cleanup(g);
+
+ if (IS_ENABLED(CONFIG_GK20A_DEVFREQ))
+ gk20a_scale_exit(dev);
+
+ if (g->remove_support)
+ g->remove_support(g);
+
+ gk20a_ce_destroy(g);
+
+#ifdef CONFIG_ARCH_TEGRA_18x_SOC
+ nvgpu_clk_arb_cleanup_arbiter(g);
+#endif
+
+ gk20a_user_deinit(dev, &nvgpu_class);
+
+ debugfs_remove_recursive(platform->debugfs);
+ debugfs_remove_recursive(platform->debugfs_alias);
+
+ gk20a_remove_sysfs(dev);
+
+ if (platform->secure_buffer.destroy)
+ platform->secure_buffer.destroy(dev,
+ &platform->secure_buffer);
+
+ if (pm_runtime_enabled(dev))
+ pm_runtime_disable(dev);
+
+ if (platform->remove)
+ platform->remove(dev);
+
+ set_gk20a(pdev, NULL);
+ gk20a_put(g);
+
+ gk20a_dbg_fn("removed");
+
+ return 0;
+}
+
+static struct platform_driver gk20a_driver = {
+ .probe = gk20a_probe,
+ .remove = __exit_p(gk20a_remove),
+ .shutdown = gk20a_pm_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "gk20a",
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#endif
+#ifdef CONFIG_OF
+ .of_match_table = tegra_gk20a_of_match,
+#endif
+#ifdef CONFIG_PM
+ .pm = &gk20a_pm_ops,
+#endif
+ .suppress_bind_attrs = true,
+ }
+};
+
+struct class nvgpu_class = {
+ .owner = THIS_MODULE,
+ .name = CLASS_NAME,
+};
+
+static int __init gk20a_init(void)
+{
+
+ int ret;
+
+ ret = class_register(&nvgpu_class);
+ if (ret)
+ return ret;
+
+ ret = nvgpu_pci_init();
+ if (ret)
+ return ret;
+
+ return platform_driver_register(&gk20a_driver);
+}
+
+static void __exit gk20a_exit(void)
+{
+ nvgpu_pci_exit();
+ platform_driver_unregister(&gk20a_driver);
+ class_unregister(&nvgpu_class);
+}
+
+MODULE_LICENSE("GPL v2");
+module_init(gk20a_init);
+module_exit(gk20a_exit);
diff --git a/drivers/gpu/nvgpu/common/linux/module.h b/drivers/gpu/nvgpu/common/linux/module.h
new file mode 100644
index 000000000..45fa2f5c4
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/module.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+#ifndef __NVGPU_COMMON_LINUX_MODULE_H__
+#define __NVGPU_COMMON_LINUX_MODULE_H__
+
+struct gk20a;
+struct device;
+
+int gk20a_pm_finalize_poweron(struct device *dev);
+void gk20a_remove_support(struct gk20a *g);
+
+#endif
diff --git a/drivers/gpu/nvgpu/pci.c b/drivers/gpu/nvgpu/common/linux/pci.c
similarity index 99%
rename from drivers/gpu/nvgpu/pci.c
rename to drivers/gpu/nvgpu/common/linux/pci.c
index fb54ae18a..f90b3a6ee 100644
--- a/drivers/gpu/nvgpu/pci.c
+++ b/drivers/gpu/nvgpu/common/linux/pci.c
@@ -24,6 +24,7 @@
#include "gk20a/gk20a.h"
#include "gk20a/platform_gk20a.h"
#include "clk/clk.h"
+#include "module.h"
#include "pci.h"
diff --git a/drivers/gpu/nvgpu/pci.h b/drivers/gpu/nvgpu/common/linux/pci.h
similarity index 100%
rename from drivers/gpu/nvgpu/pci.h
rename to drivers/gpu/nvgpu/common/linux/pci.h
diff --git a/drivers/gpu/nvgpu/gk20a/debug_gk20a.c b/drivers/gpu/nvgpu/gk20a/debug_gk20a.c
index 85b24f2ea..1a9ffe774 100644
--- a/drivers/gpu/nvgpu/gk20a/debug_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/debug_gk20a.c
@@ -228,6 +228,74 @@ void gk20a_init_debug_ops(struct gpu_ops *gops)
gops->debug.show_dump = gk20a_debug_show_dump;
}
+#ifdef CONFIG_DEBUG_FS
+static int railgate_residency_show(struct seq_file *s, void *data)
+{
+ struct device *dev = s->private;
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+ struct gk20a *g = get_gk20a(dev);
+ unsigned long time_since_last_state_transition_ms;
+ unsigned long total_rail_gate_time_ms;
+ unsigned long total_rail_ungate_time_ms;
+
+ if (platform->is_railgated(dev)) {
+ time_since_last_state_transition_ms =
+ jiffies_to_msecs(jiffies -
+ g->pstats.last_rail_gate_complete);
+ total_rail_ungate_time_ms = g->pstats.total_rail_ungate_time_ms;
+ total_rail_gate_time_ms =
+ g->pstats.total_rail_gate_time_ms +
+ time_since_last_state_transition_ms;
+ } else {
+ time_since_last_state_transition_ms =
+ jiffies_to_msecs(jiffies -
+ g->pstats.last_rail_ungate_complete);
+ total_rail_gate_time_ms = g->pstats.total_rail_gate_time_ms;
+ total_rail_ungate_time_ms =
+ g->pstats.total_rail_ungate_time_ms +
+ time_since_last_state_transition_ms;
+ }
+
+ seq_printf(s, "Time with Rails Gated: %lu ms\n"
+ "Time with Rails UnGated: %lu ms\n"
+ "Total railgating cycles: %lu\n",
+ total_rail_gate_time_ms,
+ total_rail_ungate_time_ms,
+ g->pstats.railgating_cycle_count - 1);
+ return 0;
+
+}
+
+static int railgate_residency_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, railgate_residency_show, inode->i_private);
+}
+
+static const struct file_operations railgate_residency_fops = {
+ .open = railgate_residency_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+int gk20a_railgating_debugfs_init(struct device *dev)
+{
+ struct dentry *d;
+ struct gk20a_platform *platform = dev_get_drvdata(dev);
+
+ if (!platform->can_railgate)
+ return 0;
+
+ d = debugfs_create_file(
+ "railgate_residency", S_IRUGO|S_IWUSR, platform->debugfs, dev,
+ &railgate_residency_fops);
+ if (!d)
+ return -ENOMEM;
+
+ return 0;
+}
+#endif
+
void gk20a_debug_init(struct device *dev, const char *debugfs_symlink)
{
struct gk20a_platform *platform = dev_get_drvdata(dev);
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c
index 2a80157d8..b3f4e5fe7 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.c
@@ -16,25 +16,7 @@
* along with this program. If not, see .
*/
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
#include
-#include
-#include
#include
#include
@@ -42,26 +24,22 @@
#include
#include
+#include
+
#include "gk20a.h"
-#include "debug_gk20a.h"
#include "channel_sync_gk20a.h"
-#include "gk20a_scale.h"
#include "ctxsw_trace_gk20a.h"
#include "dbg_gpu_gk20a.h"
#include "mc_gk20a.h"
#include "hal.h"
#include "vgpu/vgpu.h"
-#include "pci.h"
#include "bus_gk20a.h"
#ifdef CONFIG_ARCH_TEGRA_18x_SOC
#include "pstate/pstate.h"
#endif
-#define CREATE_TRACE_POINTS
-#include
-
#ifdef CONFIG_TEGRA_19x_GPU
#include "nvgpu_gpuid_t19x.h"
#endif
@@ -70,93 +48,6 @@
#include
#include
-
-#ifdef CONFIG_ARM64
-#define __cpuc_flush_dcache_area __flush_dcache_area
-#endif
-
-#define CLASS_NAME "nvidia-gpu"
-/* TODO: Change to e.g. "nvidia-gpu%s" once we have symlinks in place. */
-
-#define GK20A_NUM_CDEVS 7
-
-#define GK20A_WAIT_FOR_IDLE_MS 2000
-
-static int gk20a_pm_prepare_poweroff(struct device *dev);
-
-#ifdef CONFIG_DEBUG_FS
-static int railgate_residency_show(struct seq_file *s, void *data)
-{
- struct device *dev = s->private;
- struct gk20a_platform *platform = dev_get_drvdata(dev);
- struct gk20a *g = get_gk20a(dev);
- unsigned long time_since_last_state_transition_ms;
- unsigned long total_rail_gate_time_ms;
- unsigned long total_rail_ungate_time_ms;
-
- if (platform->is_railgated(dev)) {
- time_since_last_state_transition_ms =
- jiffies_to_msecs(jiffies -
- g->pstats.last_rail_gate_complete);
- total_rail_ungate_time_ms = g->pstats.total_rail_ungate_time_ms;
- total_rail_gate_time_ms =
- g->pstats.total_rail_gate_time_ms +
- time_since_last_state_transition_ms;
- } else {
- time_since_last_state_transition_ms =
- jiffies_to_msecs(jiffies -
- g->pstats.last_rail_ungate_complete);
- total_rail_gate_time_ms = g->pstats.total_rail_gate_time_ms;
- total_rail_ungate_time_ms =
- g->pstats.total_rail_ungate_time_ms +
- time_since_last_state_transition_ms;
- }
-
- seq_printf(s, "Time with Rails Gated: %lu ms\n"
- "Time with Rails UnGated: %lu ms\n"
- "Total railgating cycles: %lu\n",
- total_rail_gate_time_ms,
- total_rail_ungate_time_ms,
- g->pstats.railgating_cycle_count - 1);
- return 0;
-
-}
-
-static int railgate_residency_open(struct inode *inode, struct file *file)
-{
- return single_open(file, railgate_residency_show, inode->i_private);
-}
-
-static const struct file_operations railgate_residency_fops = {
- .open = railgate_residency_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-int gk20a_railgating_debugfs_init(struct device *dev)
-{
- struct dentry *d;
- struct gk20a_platform *platform = dev_get_drvdata(dev);
-
- if (!platform->can_railgate)
- return 0;
-
- d = debugfs_create_file(
- "railgate_residency", S_IRUGO|S_IWUSR, platform->debugfs, dev,
- &railgate_residency_fops);
- if (!d)
- return -ENOMEM;
-
- return 0;
-}
-#endif
-
-static inline void set_gk20a(struct platform_device *pdev, struct gk20a *gk20a)
-{
- gk20a_get_platform(&pdev->dev)->g = gk20a;
-}
-
void __nvgpu_check_gpu_state(struct gk20a *g)
{
u32 boot_0 = g->ops.mc.boot_0(g, NULL, NULL, NULL);
@@ -199,181 +90,6 @@ void __gk20a_warn_on_no_regs(void)
WARN_ONCE(1, "Attempted access to GPU regs after unmapping!");
}
-void __iomem *gk20a_ioremap_resource(struct platform_device *dev, int i,
- struct resource **out)
-{
- struct resource *r = platform_get_resource(dev, IORESOURCE_MEM, i);
- if (!r)
- return NULL;
- if (out)
- *out = r;
- return devm_ioremap_resource(&dev->dev, r);
-}
-
-static irqreturn_t gk20a_intr_isr_stall(int irq, void *dev_id)
-{
- struct gk20a *g = dev_id;
-
- return g->ops.mc.isr_stall(g);
-}
-
-static irqreturn_t gk20a_intr_isr_nonstall(int irq, void *dev_id)
-{
- struct gk20a *g = dev_id;
-
- return g->ops.mc.isr_nonstall(g);
-}
-
-static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id)
-{
- struct gk20a *g = dev_id;
- return g->ops.mc.isr_thread_stall(g);
-}
-
-void gk20a_remove_support(struct gk20a *g)
-{
-#ifdef CONFIG_TEGRA_COMMON
- tegra_unregister_idle_unidle();
-#endif
- if (g->dbg_regops_tmp_buf)
- nvgpu_kfree(g, g->dbg_regops_tmp_buf);
-
- if (g->pmu.remove_support)
- g->pmu.remove_support(&g->pmu);
-
- if (g->gr.remove_support)
- g->gr.remove_support(&g->gr);
-
- if (g->mm.remove_ce_support)
- g->mm.remove_ce_support(&g->mm);
-
- if (g->fifo.remove_support)
- g->fifo.remove_support(&g->fifo);
-
- if (g->mm.remove_support)
- g->mm.remove_support(&g->mm);
-
- if (g->sim.remove_support)
- g->sim.remove_support(&g->sim);
-
- /* free mappings to registers, etc */
-
- if (g->regs) {
- iounmap(g->regs);
- g->regs = NULL;
- }
- if (g->bar1) {
- iounmap(g->bar1);
- g->bar1 = NULL;
- }
-}
-
-static int gk20a_init_support(struct platform_device *dev)
-{
- int err = 0;
- struct gk20a *g = get_gk20a(&dev->dev);
-
-#ifdef CONFIG_TEGRA_COMMON
- tegra_register_idle_unidle(gk20a_do_idle, gk20a_do_unidle);
-#endif
-
- g->regs = gk20a_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM,
- &g->reg_mem);
- if (IS_ERR(g->regs)) {
- nvgpu_err(g, "failed to remap gk20a registers\n");
- err = PTR_ERR(g->regs);
- goto fail;
- }
-
- g->bar1 = gk20a_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM,
- &g->bar1_mem);
- if (IS_ERR(g->bar1)) {
- nvgpu_err(g, "failed to remap gk20a bar1\n");
- err = PTR_ERR(g->bar1);
- goto fail;
- }
-
- if (nvgpu_platform_is_simulation(g)) {
- err = gk20a_init_sim_support(dev);
- if (err)
- goto fail;
- }
-
- return 0;
-
- fail:
- return err;
-}
-
-static int gk20a_pm_prepare_poweroff(struct device *dev)
-{
- struct gk20a *g = get_gk20a(dev);
- int ret = 0;
- struct gk20a_platform *platform = gk20a_get_platform(dev);
-
- gk20a_dbg_fn("");
-
- nvgpu_mutex_acquire(&g->poweroff_lock);
-
- if (!g->power_on)
- goto done;
-
- if (gk20a_fifo_is_engine_busy(g)) {
- nvgpu_mutex_release(&g->poweroff_lock);
- return -EBUSY;
- }
- gk20a_scale_suspend(dev);
-
- /* cancel any pending cde work */
- gk20a_cde_suspend(g);
-
- gk20a_ce_suspend(g);
-
- ret = gk20a_channel_suspend(g);
- if (ret)
- goto done;
-
- /* disable elpg before gr or fifo suspend */
- if (g->ops.pmu.is_pmu_supported(g))
- ret |= gk20a_pmu_destroy(g);
- /*
- * After this point, gk20a interrupts should not get
- * serviced.
- */
- disable_irq(g->irq_stall);
- if (g->irq_stall != g->irq_nonstall)
- disable_irq(g->irq_nonstall);
-
- ret |= gk20a_gr_suspend(g);
- ret |= gk20a_mm_suspend(g);
- ret |= gk20a_fifo_suspend(g);
-
- if (g->ops.pmu.mclk_deinit)
- g->ops.pmu.mclk_deinit(g);
-
- /* Disable GPCPLL */
- if (g->ops.clk.suspend_clk_support)
- ret |= g->ops.clk.suspend_clk_support(g);
-
-#ifdef CONFIG_ARCH_TEGRA_18x_SOC
- if (g->ops.pmupstate)
- gk20a_deinit_pstate_support(g);
-#endif
- g->power_on = false;
-
- /* Decrement platform power refcount */
- if (platform->idle)
- platform->idle(dev);
-
- /* Stop CPU from accessing the GPU registers. */
- gk20a_lockout_registers(g);
-
-done:
- nvgpu_mutex_release(&g->poweroff_lock);
-
- return ret;
-}
-
static int gk20a_detect_chip(struct gk20a *g)
{
struct nvgpu_gpu_characteristics *gpu = &g->gpu_characteristics;
@@ -392,36 +108,58 @@ static int gk20a_detect_chip(struct gk20a *g)
return gpu_init_hal(g);
}
-int gk20a_pm_finalize_poweron(struct device *dev)
+int gk20a_prepare_poweroff(struct gk20a *g)
{
- struct gk20a *g = get_gk20a(dev);
- struct gk20a_platform *platform = gk20a_get_platform(dev);
- int err, nice_value;
+ int ret = 0;
+
+ gk20a_dbg_fn("");
+
+ if (gk20a_fifo_is_engine_busy(g))
+ return -EBUSY;
+
+ /* cancel any pending cde work */
+ gk20a_cde_suspend(g);
+
+ gk20a_ce_suspend(g);
+
+ ret = gk20a_channel_suspend(g);
+ if (ret)
+ return ret;
+
+ /* disable elpg before gr or fifo suspend */
+ if (g->ops.pmu.is_pmu_supported(g))
+ ret |= gk20a_pmu_destroy(g);
+
+ ret |= gk20a_gr_suspend(g);
+ ret |= gk20a_mm_suspend(g);
+ ret |= gk20a_fifo_suspend(g);
+
+ if (g->ops.pmu.mclk_deinit)
+ g->ops.pmu.mclk_deinit(g);
+
+ /* Disable GPCPLL */
+ if (g->ops.clk.suspend_clk_support)
+ ret |= g->ops.clk.suspend_clk_support(g);
+
+#ifdef CONFIG_ARCH_TEGRA_18x_SOC
+ if (g->ops.pmupstate)
+ gk20a_deinit_pstate_support(g);
+#endif
+ g->power_on = false;
+
+ return ret;
+}
+
+int gk20a_finalize_poweron(struct gk20a *g)
+{
+ struct gk20a_platform *platform = gk20a_get_platform(g->dev);
+ int err;
gk20a_dbg_fn("");
if (g->power_on)
return 0;
- trace_gk20a_finalize_poweron(g->name);
-
- /* Increment platform power refcount */
- if (platform->busy) {
- err = platform->busy(dev);
- if (err < 0) {
- nvgpu_err(g, "%s: failed to poweron platform dependency\n",
- __func__);
- goto done;
- }
- }
-
- err = gk20a_restore_registers(g);
- if (err)
- return err;
-
- nice_value = task_nice(current);
- set_user_nice(current, -20);
-
g->power_on = true;
err = gk20a_detect_chip(g);
@@ -586,31 +324,18 @@ int gk20a_pm_finalize_poweron(struct device *dev)
g->ops.fb.set_debug_mode(g, g->mmu_debug_ctrl);
gk20a_channel_resume(g);
- set_user_nice(current, nice_value);
-
- gk20a_scale_resume(dev);
-
- trace_gk20a_finalize_poweron_done(g->name);
-
- if (platform->has_cde)
- gk20a_init_cde_support(g);
gk20a_init_ce_support(g);
gk20a_init_mm_ce_context(g);
- enable_irq(g->irq_stall);
- if (g->irq_stall != g->irq_nonstall)
- enable_irq(g->irq_nonstall);
- g->irqs_enabled = 1;
-
if (g->ops.xve.available_speeds) {
u32 speed;
if (platform->disable_aspm && g->ops.xve.disable_aspm)
g->ops.xve.disable_aspm(g);
- g->ops.xve.sw_init(dev);
+ g->ops.xve.sw_init(g->dev);
g->ops.xve.available_speeds(g, &speed);
/* Set to max speed */
@@ -629,515 +354,15 @@ done:
return err;
}
-static struct of_device_id tegra_gk20a_of_match[] = {
-#ifdef CONFIG_TEGRA_GK20A
- { .compatible = "nvidia,tegra124-gk20a",
- .data = &gk20a_tegra_platform },
- { .compatible = "nvidia,tegra210-gm20b",
- .data = &gm20b_tegra_platform },
-#ifdef CONFIG_ARCH_TEGRA_18x_SOC
- { .compatible = "nvidia,tegra186-gp10b",
- .data = &gp10b_tegra_platform },
-#endif
-#ifdef CONFIG_TEGRA_19x_GPU
- { .compatible = TEGRA_19x_GPU_COMPAT_TEGRA,
- .data = &t19x_gpu_tegra_platform },
-#endif
-#ifdef CONFIG_TEGRA_GR_VIRTUALIZATION
- { .compatible = "nvidia,tegra124-gk20a-vgpu",
- .data = &vgpu_tegra_platform },
-#endif
-#else
- { .compatible = "nvidia,tegra124-gk20a",
- .data = &gk20a_generic_platform },
- { .compatible = "nvidia,tegra210-gm20b",
- .data = &gk20a_generic_platform },
-#ifdef CONFIG_ARCH_TEGRA_18x_SOC
- { .compatible = TEGRA_18x_GPU_COMPAT_TEGRA,
- .data = &gk20a_generic_platform },
-#endif
-
-#endif
- { .compatible = "nvidia,generic-gk20a",
- .data = &gk20a_generic_platform },
- { .compatible = "nvidia,generic-gm20b",
- .data = &gk20a_generic_platform },
-#ifdef CONFIG_ARCH_TEGRA_18x_SOC
- { .compatible = "nvidia,generic-gp10b",
- .data = &gk20a_generic_platform },
-#endif
- { },
-};
-
-static int gk20a_pm_railgate(struct device *dev)
+/*
+ * Check if the device can go busy. Basically if the driver is currently
+ * in the process of dying then do not let new places make the driver busy.
+ */
+int gk20a_can_busy(struct gk20a *g)
{
- struct gk20a_platform *platform = dev_get_drvdata(dev);
- int ret = 0;
-#ifdef CONFIG_DEBUG_FS
- struct gk20a *g = get_gk20a(dev);
-
- g->pstats.last_rail_gate_start = jiffies;
-
- if (g->pstats.railgating_cycle_count >= 1)
- g->pstats.total_rail_ungate_time_ms =
- g->pstats.total_rail_ungate_time_ms +
- jiffies_to_msecs(g->pstats.last_rail_gate_start -
- g->pstats.last_rail_ungate_complete);
-#endif
-
- if (platform->railgate)
- ret = platform->railgate(dev);
-
-#ifdef CONFIG_DEBUG_FS
- g->pstats.last_rail_gate_complete = jiffies;
-#endif
-
- return ret;
-}
-
-static int gk20a_pm_unrailgate(struct device *dev)
-{
- struct gk20a_platform *platform = dev_get_drvdata(dev);
- int ret = 0;
- struct gk20a *g = get_gk20a(dev);
-
-#ifdef CONFIG_DEBUG_FS
- g->pstats.last_rail_ungate_start = jiffies;
- if (g->pstats.railgating_cycle_count >= 1)
- g->pstats.total_rail_gate_time_ms =
- g->pstats.total_rail_gate_time_ms +
- jiffies_to_msecs(g->pstats.last_rail_ungate_start -
- g->pstats.last_rail_gate_complete);
-
- g->pstats.railgating_cycle_count++;
-#endif
-
- trace_gk20a_pm_unrailgate(g->name);
-
- if (platform->unrailgate) {
- nvgpu_mutex_acquire(&platform->railgate_lock);
- ret = platform->unrailgate(dev);
- nvgpu_mutex_release(&platform->railgate_lock);
- }
-
-#ifdef CONFIG_DEBUG_FS
- g->pstats.last_rail_ungate_complete = jiffies;
-#endif
-
- return ret;
-}
-
-static void gk20a_pm_shutdown(struct platform_device *pdev)
-{
- struct gk20a_platform *platform = platform_get_drvdata(pdev);
- struct gk20a *g = platform->g;
- int err;
-
- nvgpu_info(g, "shutting down");
-
- /* vgpu has nothing to clean up currently */
- if (gk20a_gpu_is_virtual(&pdev->dev))
- return;
-
- gk20a_driver_start_unload(g);
-
- /* If GPU is already railgated,
- * just prevent more requests, and return */
- if (platform->is_railgated && platform->is_railgated(&pdev->dev)) {
- __pm_runtime_disable(&pdev->dev, false);
- nvgpu_info(g, "already railgated, shut down complete");
- return;
- }
-
- /* Prevent more requests by disabling Runtime PM */
- __pm_runtime_disable(&pdev->dev, false);
-
- err = gk20a_wait_for_idle(&pdev->dev);
- if (err) {
- nvgpu_err(g, "failed to idle GPU, err=%d", err);
- goto finish;
- }
-
- err = gk20a_fifo_disable_all_engine_activity(g, true);
- if (err) {
- nvgpu_err(g, "failed to disable engine activity, err=%d",
- err);
- goto finish;
- }
-
- err = gk20a_fifo_wait_engine_idle(g);
- if (err) {
- nvgpu_err(g, "failed to idle engines, err=%d",
- err);
- goto finish;
- }
-
- if (gk20a_gpu_is_virtual(&pdev->dev))
- err = vgpu_pm_prepare_poweroff(&pdev->dev);
- else
- err = gk20a_pm_prepare_poweroff(&pdev->dev);
- if (err) {
- nvgpu_err(g, "failed to prepare for poweroff, err=%d",
- err);
- goto finish;
- }
-
- err = gk20a_pm_railgate(&pdev->dev);
- if (err)
- nvgpu_err(g, "failed to railgate, err=%d", err);
-
-finish:
- nvgpu_info(g, "shut down complete\n");
-}
-
-#ifdef CONFIG_PM
-static int gk20a_pm_runtime_resume(struct device *dev)
-{
- int err = 0;
-
- err = gk20a_pm_unrailgate(dev);
- if (err)
- goto fail;
-
- err = gk20a_pm_finalize_poweron(dev);
- if (err)
- goto fail_poweron;
-
- return 0;
-
-fail_poweron:
- gk20a_pm_railgate(dev);
-fail:
- return err;
-}
-
-static int gk20a_pm_runtime_suspend(struct device *dev)
-{
- int err = 0;
-
- err = gk20a_pm_prepare_poweroff(dev);
- if (err)
- goto fail;
-
- err = gk20a_pm_railgate(dev);
- if (err)
- goto fail_railgate;
-
- return 0;
-
-fail_railgate:
- gk20a_pm_finalize_poweron(dev);
-fail:
- pm_runtime_mark_last_busy(dev);
- return err;
-}
-
-static int gk20a_pm_suspend(struct device *dev)
-{
- struct gk20a_platform *platform = dev_get_drvdata(dev);
- struct gk20a *g = get_gk20a(dev);
- int ret = 0;
-
- if (platform->user_railgate_disabled)
- gk20a_idle_nosuspend(dev);
-
- if (atomic_read(&dev->power.usage_count) > 1) {
- ret = -EBUSY;
- goto fail;
- }
-
- if (!g->power_on)
+ if (g->driver_is_dying)
return 0;
-
- ret = gk20a_pm_runtime_suspend(dev);
- if (ret)
- goto fail;
-
- if (platform->suspend)
- platform->suspend(dev);
-
- g->suspended = true;
-
- return 0;
-
-fail:
- if (platform->user_railgate_disabled)
- gk20a_busy_noresume(dev);
-
- return ret;
-}
-
-static int gk20a_pm_resume(struct device *dev)
-{
- struct gk20a *g = get_gk20a(dev);
- struct gk20a_platform *platform = dev_get_drvdata(dev);
- int ret = 0;
-
- if (platform->user_railgate_disabled)
- gk20a_busy_noresume(dev);
-
- if (!g->suspended)
- return 0;
-
- ret = gk20a_pm_runtime_resume(dev);
-
- g->suspended = false;
-
- return ret;
-}
-
-static const struct dev_pm_ops gk20a_pm_ops = {
- .runtime_resume = gk20a_pm_runtime_resume,
- .runtime_suspend = gk20a_pm_runtime_suspend,
- .resume = gk20a_pm_resume,
- .suspend = gk20a_pm_suspend,
-};
-#endif
-
-int gk20a_pm_init(struct device *dev)
-{
- struct gk20a_platform *platform = dev_get_drvdata(dev);
- int err = 0;
-
- gk20a_dbg_fn("");
-
- /* Initialise pm runtime */
- if (platform->railgate_delay) {
- pm_runtime_set_autosuspend_delay(dev,
- platform->railgate_delay);
- pm_runtime_use_autosuspend(dev);
- }
-
- if (platform->can_railgate) {
- pm_runtime_enable(dev);
- if (!pm_runtime_enabled(dev))
- gk20a_pm_unrailgate(dev);
- else
- gk20a_pm_railgate(dev);
- } else {
- __pm_runtime_disable(dev, false);
- gk20a_pm_unrailgate(dev);
- }
-
- return err;
-}
-
-int gk20a_secure_page_alloc(struct device *dev)
-{
- struct gk20a_platform *platform = dev_get_drvdata(dev);
- int err = 0;
-
- if (platform->secure_page_alloc) {
- err = platform->secure_page_alloc(dev);
- if (!err)
- platform->secure_alloc_ready = true;
- }
-
- return err;
-}
-
-static int gk20a_probe(struct platform_device *dev)
-{
- struct gk20a *gk20a;
- int err;
- struct gk20a_platform *platform = NULL;
-
- if (dev->dev.of_node) {
- const struct of_device_id *match;
-
- match = of_match_device(tegra_gk20a_of_match, &dev->dev);
- if (match)
- platform = (struct gk20a_platform *)match->data;
- } else
- platform = (struct gk20a_platform *)dev->dev.platform_data;
-
- if (!platform) {
- dev_err(&dev->dev, "no platform data\n");
- return -ENODATA;
- }
-
- gk20a_dbg_fn("");
-
- platform_set_drvdata(dev, platform);
-
- if (gk20a_gpu_is_virtual(&dev->dev))
- return vgpu_probe(dev);
-
- gk20a = kzalloc(sizeof(struct gk20a), GFP_KERNEL);
- if (!gk20a) {
- dev_err(&dev->dev, "couldn't allocate gk20a support");
- return -ENOMEM;
- }
-
- set_gk20a(dev, gk20a);
- gk20a->dev = &dev->dev;
-
- if (nvgpu_platform_is_simulation(gk20a))
- platform->is_fmodel = true;
-
- nvgpu_kmem_init(gk20a);
-
- gk20a->irq_stall = platform_get_irq(dev, 0);
- gk20a->irq_nonstall = platform_get_irq(dev, 1);
- if (gk20a->irq_stall < 0 || gk20a->irq_nonstall < 0)
- return -ENXIO;
-
- err = devm_request_threaded_irq(&dev->dev,
- gk20a->irq_stall,
- gk20a_intr_isr_stall,
- gk20a_intr_thread_stall,
- 0, "gk20a_stall", gk20a);
- if (err) {
- dev_err(&dev->dev,
- "failed to request stall intr irq @ %d\n",
- gk20a->irq_stall);
- return err;
- }
- err = devm_request_irq(&dev->dev,
- gk20a->irq_nonstall,
- gk20a_intr_isr_nonstall,
- 0, "gk20a_nonstall", gk20a);
- if (err) {
- dev_err(&dev->dev,
- "failed to request non-stall intr irq @ %d\n",
- gk20a->irq_nonstall);
- return err;
- }
- disable_irq(gk20a->irq_stall);
- if (gk20a->irq_stall != gk20a->irq_nonstall)
- disable_irq(gk20a->irq_nonstall);
-
- /*
- * is_fmodel needs to be in gk20a struct for deferred teardown
- */
- gk20a->is_fmodel = platform->is_fmodel;
-
- err = gk20a_init_support(dev);
- if (err)
- return err;
-
-#ifdef CONFIG_RESET_CONTROLLER
- platform->reset_control = devm_reset_control_get(&dev->dev, NULL);
- if (IS_ERR(platform->reset_control))
- platform->reset_control = NULL;
-#endif
-
- err = nvgpu_probe(gk20a, "gpu.0", INTERFACE_NAME, &nvgpu_class);
- if (err)
- return err;
-
- err = gk20a_pm_init(&dev->dev);
- if (err) {
- dev_err(&dev->dev, "pm init failed");
- return err;
- }
-
- gk20a->mm.has_physical_mode = !nvgpu_is_hypervisor_mode(gk20a);
-
- return 0;
-}
-
-static int __exit gk20a_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct gk20a *g = get_gk20a(dev);
- struct gk20a_platform *platform = gk20a_get_platform(dev);
-
- gk20a_dbg_fn("");
-
- if (gk20a_gpu_is_virtual(dev))
- return vgpu_remove(pdev);
-
- if (platform->has_cde)
- gk20a_cde_destroy(g);
-
- gk20a_ctxsw_trace_cleanup(g);
-
- gk20a_sched_ctrl_cleanup(g);
-
- if (IS_ENABLED(CONFIG_GK20A_DEVFREQ))
- gk20a_scale_exit(dev);
-
-#ifdef CONFIG_ARCH_TEGRA_18x_SOC
- nvgpu_clk_arb_cleanup_arbiter(g);
-#endif
-
- gk20a_user_deinit(dev, &nvgpu_class);
-
- debugfs_remove_recursive(platform->debugfs);
- debugfs_remove_recursive(platform->debugfs_alias);
-
- gk20a_remove_sysfs(dev);
-
- if (platform->secure_buffer.destroy)
- platform->secure_buffer.destroy(dev,
- &platform->secure_buffer);
-
- if (pm_runtime_enabled(dev))
- pm_runtime_disable(dev);
-
- if (platform->remove)
- platform->remove(dev);
-
- set_gk20a(pdev, NULL);
- gk20a_put(g);
-
- gk20a_dbg_fn("removed");
-
- return 0;
-}
-
-static struct platform_driver gk20a_driver = {
- .probe = gk20a_probe,
- .remove = __exit_p(gk20a_remove),
- .shutdown = gk20a_pm_shutdown,
- .driver = {
- .owner = THIS_MODULE,
- .name = "gk20a",
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
-#endif
-#ifdef CONFIG_OF
- .of_match_table = tegra_gk20a_of_match,
-#endif
-#ifdef CONFIG_PM
- .pm = &gk20a_pm_ops,
-#endif
- .suppress_bind_attrs = true,
- }
-};
-
-struct class nvgpu_class = {
- .owner = THIS_MODULE,
- .name = CLASS_NAME,
-};
-
-static int __init gk20a_init(void)
-{
-
- int ret;
-
- ret = class_register(&nvgpu_class);
- if (ret)
- return ret;
-
- ret = nvgpu_pci_init();
- if (ret)
- return ret;
-
- return platform_driver_register(&gk20a_driver);
-}
-
-static void __exit gk20a_exit(void)
-{
- nvgpu_pci_exit();
- platform_driver_unregister(&gk20a_driver);
- class_unregister(&nvgpu_class);
-}
-
-void gk20a_busy_noresume(struct device *dev)
-{
- pm_runtime_get_noresume(dev);
+ return 1;
}
/*
@@ -1193,292 +418,6 @@ int gk20a_wait_for_idle(struct device *dev)
return 0;
}
-/*
- * Check if the device can go busy. Basically if the driver is currently
- * in the process of dying then do not let new places make the driver busy.
- */
-static int gk20a_can_busy(struct gk20a *g)
-{
- if (g->driver_is_dying)
- return 0;
- return 1;
-}
-
-int gk20a_busy(struct gk20a *g)
-{
- int ret = 0;
- struct device *dev;
-
- if (!g)
- return -ENODEV;
-
- atomic_inc(&g->usage_count);
-
- down_read(&g->busy_lock);
-
- if (!gk20a_can_busy(g)) {
- ret = -ENODEV;
- atomic_dec(&g->usage_count);
- goto fail;
- }
-
- dev = g->dev;
-
- if (pm_runtime_enabled(dev)) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
- atomic_dec(&g->usage_count);
- goto fail;
- }
- } else {
- if (!g->power_on) {
- ret = gk20a_gpu_is_virtual(dev) ?
- vgpu_pm_finalize_poweron(dev)
- : gk20a_pm_finalize_poweron(dev);
- if (ret) {
- atomic_dec(&g->usage_count);
- goto fail;
- }
- }
- }
-
- gk20a_scale_notify_busy(dev);
-
-fail:
- up_read(&g->busy_lock);
-
- return ret < 0 ? ret : 0;
-}
-
-void gk20a_idle_nosuspend(struct device *dev)
-{
- pm_runtime_put_noidle(dev);
-}
-
-void gk20a_idle(struct gk20a *g)
-{
- struct device *dev;
-
- atomic_dec(&g->usage_count);
- down_read(&g->busy_lock);
-
- dev = g->dev;
-
- if (!(dev && gk20a_can_busy(g)))
- goto fail;
-
- if (pm_runtime_enabled(dev)) {
-#ifdef CONFIG_PM
- if (atomic_read(&g->dev->power.usage_count) == 1)
- gk20a_scale_notify_idle(dev);
-#endif
-
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_sync_autosuspend(dev);
-
- } else {
- gk20a_scale_notify_idle(dev);
- }
-fail:
- up_read(&g->busy_lock);
-}
-
-#ifdef CONFIG_PM
-/**
- * __gk20a_do_idle() - force the GPU to idle and railgate
- *
- * In success, this call MUST be balanced by caller with __gk20a_do_unidle()
- *
- * Acquires two locks : &g->busy_lock and &platform->railgate_lock
- * In success, we hold these locks and return
- * In failure, we release these locks and return
- */
-int __gk20a_do_idle(struct device *dev, bool force_reset)
-{
- struct gk20a *g = get_gk20a(dev);
- struct gk20a_platform *platform = dev_get_drvdata(dev);
- struct nvgpu_timeout timeout;
- int ref_cnt;
- int target_ref_cnt = 0;
- bool is_railgated;
- int err = 0;
-
- /* acquire busy lock to block other busy() calls */
- down_write(&g->busy_lock);
-
- /* acquire railgate lock to prevent unrailgate in midst of do_idle() */
- nvgpu_mutex_acquire(&platform->railgate_lock);
-
- /* check if it is already railgated ? */
- if (platform->is_railgated(dev))
- return 0;
-
- /*
- * release railgate_lock, prevent suspend by incrementing usage counter,
- * re-acquire railgate_lock
- */
- nvgpu_mutex_release(&platform->railgate_lock);
- pm_runtime_get_sync(dev);
-
- /*
- * One refcount taken in this API
- * If User disables rail gating, we take one more
- * extra refcount
- */
- if (platform->user_railgate_disabled)
- target_ref_cnt = 2;
- else
- target_ref_cnt = 1;
- nvgpu_mutex_acquire(&platform->railgate_lock);
-
- nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS,
- NVGPU_TIMER_CPU_TIMER);
-
- /* check and wait until GPU is idle (with a timeout) */
- do {
- nvgpu_msleep(1);
- ref_cnt = atomic_read(&dev->power.usage_count);
- } while (ref_cnt != target_ref_cnt && !nvgpu_timeout_expired(&timeout));
-
- if (ref_cnt != target_ref_cnt) {
- nvgpu_err(g, "failed to idle - refcount %d != 1\n",
- ref_cnt);
- goto fail_drop_usage_count;
- }
-
- /* check if global force_reset flag is set */
- force_reset |= platform->force_reset_in_do_idle;
-
- nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS,
- NVGPU_TIMER_CPU_TIMER);
-
- if (platform->can_railgate && !force_reset) {
- /*
- * Case 1 : GPU railgate is supported
- *
- * if GPU is now idle, we will have only one ref count,
- * drop this ref which will rail gate the GPU
- */
- pm_runtime_put_sync(dev);
-
- /* add sufficient delay to allow GPU to rail gate */
- nvgpu_msleep(platform->railgate_delay);
-
- /* check in loop if GPU is railgated or not */
- do {
- nvgpu_msleep(1);
- is_railgated = platform->is_railgated(dev);
- } while (!is_railgated && !nvgpu_timeout_expired(&timeout));
-
- if (is_railgated) {
- return 0;
- } else {
- nvgpu_err(g, "failed to idle in timeout\n");
- goto fail_timeout;
- }
- } else {
- /*
- * Case 2 : GPU railgate is not supported or we explicitly
- * do not want to depend on runtime PM
- *
- * if GPU is now idle, call prepare_poweroff() to save the
- * state and then do explicit railgate
- *
- * __gk20a_do_unidle() needs to unrailgate, call
- * finalize_poweron(), and then call pm_runtime_put_sync()
- * to balance the GPU usage counter
- */
-
- /* Save the GPU state */
- err = gk20a_pm_prepare_poweroff(dev);
- if (err)
- goto fail_drop_usage_count;
-
- /* railgate GPU */
- platform->railgate(dev);
-
- nvgpu_udelay(10);
-
- g->forced_reset = true;
- return 0;
- }
-
-fail_drop_usage_count:
- pm_runtime_put_noidle(dev);
-fail_timeout:
- nvgpu_mutex_release(&platform->railgate_lock);
- up_write(&g->busy_lock);
- return -EBUSY;
-}
-
-/**
- * gk20a_do_idle() - wrap up for __gk20a_do_idle() to be called
- * from outside of GPU driver
- *
- * In success, this call MUST be balanced by caller with gk20a_do_unidle()
- */
-int gk20a_do_idle(void)
-{
- struct device_node *node =
- of_find_matching_node(NULL, tegra_gk20a_of_match);
- struct platform_device *pdev = of_find_device_by_node(node);
-
- int ret = __gk20a_do_idle(&pdev->dev, true);
-
- of_node_put(node);
-
- return ret;
-}
-
-/**
- * __gk20a_do_unidle() - unblock all the tasks blocked by __gk20a_do_idle()
- */
-int __gk20a_do_unidle(struct device *dev)
-{
- struct gk20a *g = get_gk20a(dev);
- struct gk20a_platform *platform = dev_get_drvdata(dev);
-
- if (g->forced_reset) {
- /*
- * If we did a forced-reset/railgate
- * then unrailgate the GPU here first
- */
- platform->unrailgate(dev);
-
- /* restore the GPU state */
- gk20a_pm_finalize_poweron(dev);
-
- /* balance GPU usage counter */
- pm_runtime_put_sync(dev);
-
- g->forced_reset = false;
- }
-
- /* release the lock and open up all other busy() calls */
- nvgpu_mutex_release(&platform->railgate_lock);
- up_write(&g->busy_lock);
-
- return 0;
-}
-
-/**
- * gk20a_do_unidle() - wrap up for __gk20a_do_unidle()
- */
-int gk20a_do_unidle(void)
-{
- struct device_node *node =
- of_find_matching_node(NULL, tegra_gk20a_of_match);
- struct platform_device *pdev = of_find_device_by_node(node);
-
- int ret = __gk20a_do_unidle(&pdev->dev);
-
- of_node_put(node);
-
- return ret;
-}
-#endif
-
int gk20a_init_gpu_characteristics(struct gk20a *g)
{
struct nvgpu_gpu_characteristics *gpu = &g->gpu_characteristics;
@@ -1651,7 +590,3 @@ void gk20a_put(struct gk20a *g)
kref_put(&g->refcount, gk20a_free_cb);
}
-
-MODULE_LICENSE("GPL v2");
-module_init(gk20a_init);
-module_exit(gk20a_exit);
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index 60d04b644..9860910cf 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -1389,6 +1389,7 @@ int gk20a_do_unidle(void);
int __gk20a_do_idle(struct device *dev, bool force_reset);
int __gk20a_do_unidle(struct device *dev);
+int gk20a_can_busy(struct gk20a *g);
void gk20a_driver_start_unload(struct gk20a *g);
int gk20a_wait_for_idle(struct device *dev);
@@ -1431,9 +1432,8 @@ extern struct class nvgpu_class;
#define INTERFACE_NAME "nvhost%s-gpu"
-int gk20a_pm_init(struct device *dev);
-int gk20a_pm_finalize_poweron(struct device *dev);
-void gk20a_remove_support(struct gk20a *g);
+int gk20a_prepare_poweroff(struct gk20a *g);
+int gk20a_finalize_poweron(struct gk20a *g);
static inline struct tsg_gk20a *tsg_gk20a_from_ch(struct channel_gk20a *ch)
{
@@ -1476,8 +1476,4 @@ void gk20a_put(struct gk20a *g);
int gk20a_railgating_debugfs_init(struct device *dev);
#endif
-int gk20a_secure_page_alloc(struct device *dev);
-void __iomem *gk20a_ioremap_resource(struct platform_device *dev, int i,
- struct resource **out);
-
#endif /* GK20A_H */
diff --git a/drivers/gpu/nvgpu/gk20a/sim_gk20a.c b/drivers/gpu/nvgpu/gk20a/sim_gk20a.c
index 8951d5a47..5c11c1181 100644
--- a/drivers/gpu/nvgpu/gk20a/sim_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/sim_gk20a.c
@@ -103,15 +103,6 @@ int gk20a_init_sim_support(struct platform_device *pdev)
struct gk20a *g = get_gk20a(dev);
u64 phys;
- g->sim.g = g;
- g->sim.regs = gk20a_ioremap_resource(pdev, GK20A_SIM_IORESOURCE_MEM,
- &g->sim.reg_mem);
- if (IS_ERR(g->sim.regs)) {
- nvgpu_err(g, "failed to remap gk20a sim regs\n");
- err = PTR_ERR(g->sim.regs);
- goto fail;
- }
-
/* allocate sim event/msg buffers */
err = alloc_and_kmap_iopage(g, &g->sim.send_bfr.kvaddr,
&g->sim.send_bfr.phys,