gpu: nvgpu: Abstract IO aperture accessors

Add abstraction of IO aperture accessors. Add new functions
gk20a_io_exists() and gk20a_io_valid_reg() to remove dependencies to
aperture fields from common code.

Implement Linux version of the abstraction by moving gk20a_readl()
and gk20a_writel() to new Linux specific io.c. Move the fields
defining IO aperture to nvgpu_os_linux.

Add t19x specific IO aperture initialization functions and add t19x
specific section to nvgpu_os_linux.

JIRA NVGPU-259

Change-Id: I09e79cda60d11a20d1099a9aaa6d2375236e94ce
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1569698
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Terje Bergstrom
2017-09-27 13:21:44 -07:00
committed by mobile promotions
parent ff9c3fc20a
commit be3750bc9e
15 changed files with 274 additions and 144 deletions

View File

@@ -54,8 +54,8 @@ static void nvgpu_init_vars(struct gk20a *g)
nvgpu_mutex_init(&g->poweron_lock);
nvgpu_mutex_init(&g->poweroff_lock);
g->regs_saved = g->regs;
g->bar1_saved = g->bar1;
l->regs_saved = l->regs;
l->bar1_saved = l->bar1;
g->emc3d_ratio = EMC3D_DEFAULT_RATIO;

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 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.
*/
#include <nvgpu/io.h>
#include <nvgpu/types.h>
#include "os_linux.h"
#include "gk20a/gk20a.h"
void nvgpu_writel(struct gk20a *g, u32 r, u32 v)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
if (unlikely(!l->regs)) {
__gk20a_warn_on_no_regs();
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x (failed)", r, v);
} else {
writel_relaxed(v, l->regs + r);
nvgpu_smp_wmb();
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x", r, v);
}
}
u32 nvgpu_readl(struct gk20a *g, u32 r)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
u32 v = 0xffffffff;
if (unlikely(!l->regs)) {
__gk20a_warn_on_no_regs();
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x (failed)", r, v);
} else {
v = readl(l->regs + r);
if (v == 0xffffffff)
__nvgpu_check_gpu_state(g);
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x", r, v);
}
return v;
}
void nvgpu_writel_check(struct gk20a *g, u32 r, u32 v)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
if (unlikely(!l->regs)) {
__gk20a_warn_on_no_regs();
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x (failed)", r, v);
} else {
nvgpu_smp_wmb();
do {
writel_relaxed(v, l->regs + r);
} while (readl(l->regs + r) != v);
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x", r, v);
}
}
void nvgpu_bar1_writel(struct gk20a *g, u32 b, u32 v)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
if (unlikely(!l->bar1)) {
__gk20a_warn_on_no_regs();
gk20a_dbg(gpu_dbg_reg, "b=0x%x v=0x%x (failed)", b, v);
} else {
nvgpu_smp_wmb();
writel_relaxed(v, l->bar1 + b);
gk20a_dbg(gpu_dbg_reg, "b=0x%x v=0x%x", b, v);
}
}
u32 nvgpu_bar1_readl(struct gk20a *g, u32 b)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
u32 v = 0xffffffff;
if (unlikely(!l->bar1)) {
__gk20a_warn_on_no_regs();
gk20a_dbg(gpu_dbg_reg, "b=0x%x v=0x%x (failed)", b, v);
} else {
v = readl(l->bar1 + b);
gk20a_dbg(gpu_dbg_reg, "b=0x%x v=0x%x", b, v);
}
return v;
}
bool nvgpu_io_exists(struct gk20a *g)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
return l->regs != NULL;
}
bool nvgpu_io_valid_reg(struct gk20a *g, u32 r)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
return r < resource_size(l->regs);
}

View File

@@ -137,6 +137,23 @@ void gk20a_idle(struct gk20a *g)
}
}
/*
* Undoes gk20a_lockout_registers().
*/
static int gk20a_restore_registers(struct gk20a *g)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
l->regs = l->regs_saved;
l->bar1 = l->bar1_saved;
#ifdef CONFIG_TEGRA_19x_GPU
t19x_restore_registers(g);
#endif
return 0;
}
int gk20a_pm_finalize_poweron(struct device *dev)
{
struct gk20a *g = get_gk20a(dev);
@@ -198,6 +215,27 @@ done:
return err;
}
/*
* Locks out the driver from accessing GPU registers. This prevents access to
* thse registers after the GPU has been clock or power gated. This should help
* find annoying bugs where register reads and writes are silently dropped
* after the GPU has been turned off. On older chips these reads and writes can
* also lock the entire CPU up.
*/
static int gk20a_lockout_registers(struct gk20a *g)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
l->regs = NULL;
l->bar1 = NULL;
#ifdef CONFIG_TEGRA_19x_GPU
t19x_lockout_registers(g);
#endif
return 0;
}
static int gk20a_pm_prepare_poweroff(struct device *dev)
{
struct gk20a *g = get_gk20a(dev);
@@ -511,6 +549,8 @@ static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id)
void gk20a_remove_support(struct gk20a *g)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
tegra_unregister_idle_unidle(gk20a_do_idle);
nvgpu_kfree(g, g->dbg_regops_tmp_buf);
@@ -535,36 +575,41 @@ void gk20a_remove_support(struct gk20a *g)
/* free mappings to registers, etc */
if (g->regs) {
iounmap(g->regs);
g->regs = NULL;
if (l->regs) {
iounmap(l->regs);
l->regs = NULL;
}
if (g->bar1) {
iounmap(g->bar1);
g->bar1 = NULL;
if (l->bar1) {
iounmap(l->bar1);
l->bar1 = NULL;
}
#ifdef CONFIG_TEGRA_19x_GPU
t19x_remove_support(g);
#endif
}
static int gk20a_init_support(struct platform_device *dev)
{
int err = 0;
struct gk20a *g = get_gk20a(&dev->dev);
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
tegra_register_idle_unidle(gk20a_do_idle, gk20a_do_unidle, g);
g->regs = gk20a_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM,
&g->reg_mem);
if (IS_ERR(g->regs)) {
l->regs = gk20a_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM,
&l->reg_mem);
if (IS_ERR(l->regs)) {
nvgpu_err(g, "failed to remap gk20a registers");
err = PTR_ERR(g->regs);
err = PTR_ERR(l->regs);
goto fail;
}
g->bar1 = gk20a_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM,
&g->bar1_mem);
if (IS_ERR(g->bar1)) {
l->bar1 = gk20a_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM,
&l->bar1_mem);
if (IS_ERR(l->bar1)) {
nvgpu_err(g, "failed to remap gk20a bar1");
err = PTR_ERR(g->bar1);
err = PTR_ERR(l->bar1);
goto fail;
}
@@ -584,6 +629,10 @@ static int gk20a_init_support(struct platform_device *dev)
goto fail;
}
#ifdef CONFIG_TEGRA_19x_GPU
t19x_init_support(g);
#endif
return 0;
fail:

View File

@@ -13,6 +13,10 @@
#ifndef __NVGPU_COMMON_LINUX_MODULE_H__
#define __NVGPU_COMMON_LINUX_MODULE_H__
#ifdef CONFIG_TEGRA_19x_GPU
#include <nvgpu/linux/module_t19x.h>
#endif
struct gk20a;
struct device;

View File

@@ -105,9 +105,10 @@ void nvgpu_mem_end(struct gk20a *g, struct nvgpu_mem *mem)
static void pramin_access_batch_rd_n(struct gk20a *g, u32 start, u32 words, u32 **arg)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
u32 r = start, *dest_u32 = *arg;
if (!g->regs) {
if (!l->regs) {
__gk20a_warn_on_no_regs();
return;
}
@@ -182,15 +183,16 @@ void nvgpu_mem_rd_n(struct gk20a *g, struct nvgpu_mem *mem,
static void pramin_access_batch_wr_n(struct gk20a *g, u32 start, u32 words, u32 **arg)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
u32 r = start, *src_u32 = *arg;
if (!g->regs) {
if (!l->regs) {
__gk20a_warn_on_no_regs();
return;
}
while (words--) {
writel_relaxed(*src_u32++, g->regs + r);
writel_relaxed(*src_u32++, l->regs + r);
r += sizeof(u32);
}
@@ -256,15 +258,16 @@ void nvgpu_mem_wr_n(struct gk20a *g, struct nvgpu_mem *mem, u32 offset,
static void pramin_access_batch_set(struct gk20a *g, u32 start, u32 words, u32 **arg)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
u32 r = start, repeat = **arg;
if (!g->regs) {
if (!l->regs) {
__gk20a_warn_on_no_regs();
return;
}
while (words--) {
writel_relaxed(repeat, g->regs + r);
writel_relaxed(repeat, l->regs + r);
r += sizeof(u32);
}
}

View File

@@ -18,6 +18,9 @@
#include <linux/cdev.h>
#ifdef CONFIG_TEGRA_19x_GPU
#include <nvgpu/linux/os_linux_t19x.h>
#endif
#include "gk20a/gk20a.h"
#include "cde.h"
@@ -85,6 +88,17 @@ struct nvgpu_os_linux {
struct work_struct nonstall_fn_work;
struct workqueue_struct *nonstall_work_queue;
struct resource *reg_mem;
void __iomem *regs;
void __iomem *regs_saved;
struct resource *bar1_mem;
void __iomem *bar1;
void __iomem *bar1_saved;
#ifdef CONFIG_TEGRA_19x_GPU
struct nvgpu_os_linux_t19x t19x;
#endif
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
struct dentry *debugfs_alias;

View File

@@ -348,20 +348,21 @@ static int nvgpu_pci_init_support(struct pci_dev *pdev)
{
int err = 0;
struct gk20a *g = get_gk20a(&pdev->dev);
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
g->regs = ioremap(pci_resource_start(pdev, 0),
l->regs = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (IS_ERR(g->regs)) {
if (IS_ERR(l->regs)) {
nvgpu_err(g, "failed to remap gk20a registers");
err = PTR_ERR(g->regs);
err = PTR_ERR(l->regs);
goto fail;
}
g->bar1 = ioremap(pci_resource_start(pdev, 1),
l->bar1 = ioremap(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1));
if (IS_ERR(g->bar1)) {
if (IS_ERR(l->bar1)) {
nvgpu_err(g, "failed to remap gk20a bar1");
err = PTR_ERR(g->bar1);
err = PTR_ERR(l->bar1);
goto fail;
}