mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
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:
committed by
mobile promotions
parent
ff9c3fc20a
commit
be3750bc9e
@@ -46,6 +46,7 @@ nvgpu-y := \
|
|||||||
common/linux/intr.o \
|
common/linux/intr.o \
|
||||||
common/linux/sysfs.o \
|
common/linux/sysfs.o \
|
||||||
common/linux/cde.o \
|
common/linux/cde.o \
|
||||||
|
common/linux/io.o \
|
||||||
common/mm/nvgpu_allocator.o \
|
common/mm/nvgpu_allocator.o \
|
||||||
common/mm/bitmap_allocator.o \
|
common/mm/bitmap_allocator.o \
|
||||||
common/mm/buddy_allocator.o \
|
common/mm/buddy_allocator.o \
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ static void nvgpu_init_vars(struct gk20a *g)
|
|||||||
nvgpu_mutex_init(&g->poweron_lock);
|
nvgpu_mutex_init(&g->poweron_lock);
|
||||||
nvgpu_mutex_init(&g->poweroff_lock);
|
nvgpu_mutex_init(&g->poweroff_lock);
|
||||||
|
|
||||||
g->regs_saved = g->regs;
|
l->regs_saved = l->regs;
|
||||||
g->bar1_saved = g->bar1;
|
l->bar1_saved = l->bar1;
|
||||||
|
|
||||||
g->emc3d_ratio = EMC3D_DEFAULT_RATIO;
|
g->emc3d_ratio = EMC3D_DEFAULT_RATIO;
|
||||||
|
|
||||||
|
|||||||
110
drivers/gpu/nvgpu/common/linux/io.c
Normal file
110
drivers/gpu/nvgpu/common/linux/io.c
Normal 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);
|
||||||
|
}
|
||||||
@@ -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)
|
int gk20a_pm_finalize_poweron(struct device *dev)
|
||||||
{
|
{
|
||||||
struct gk20a *g = get_gk20a(dev);
|
struct gk20a *g = get_gk20a(dev);
|
||||||
@@ -198,6 +215,27 @@ done:
|
|||||||
return err;
|
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)
|
static int gk20a_pm_prepare_poweroff(struct device *dev)
|
||||||
{
|
{
|
||||||
struct gk20a *g = get_gk20a(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)
|
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);
|
tegra_unregister_idle_unidle(gk20a_do_idle);
|
||||||
|
|
||||||
nvgpu_kfree(g, g->dbg_regops_tmp_buf);
|
nvgpu_kfree(g, g->dbg_regops_tmp_buf);
|
||||||
@@ -535,36 +575,41 @@ void gk20a_remove_support(struct gk20a *g)
|
|||||||
|
|
||||||
/* free mappings to registers, etc */
|
/* free mappings to registers, etc */
|
||||||
|
|
||||||
if (g->regs) {
|
if (l->regs) {
|
||||||
iounmap(g->regs);
|
iounmap(l->regs);
|
||||||
g->regs = NULL;
|
l->regs = NULL;
|
||||||
}
|
}
|
||||||
if (g->bar1) {
|
if (l->bar1) {
|
||||||
iounmap(g->bar1);
|
iounmap(l->bar1);
|
||||||
g->bar1 = NULL;
|
l->bar1 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TEGRA_19x_GPU
|
||||||
|
t19x_remove_support(g);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gk20a_init_support(struct platform_device *dev)
|
static int gk20a_init_support(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct gk20a *g = get_gk20a(&dev->dev);
|
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);
|
tegra_register_idle_unidle(gk20a_do_idle, gk20a_do_unidle, g);
|
||||||
|
|
||||||
g->regs = gk20a_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM,
|
l->regs = gk20a_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM,
|
||||||
&g->reg_mem);
|
&l->reg_mem);
|
||||||
if (IS_ERR(g->regs)) {
|
if (IS_ERR(l->regs)) {
|
||||||
nvgpu_err(g, "failed to remap gk20a registers");
|
nvgpu_err(g, "failed to remap gk20a registers");
|
||||||
err = PTR_ERR(g->regs);
|
err = PTR_ERR(l->regs);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
g->bar1 = gk20a_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM,
|
l->bar1 = gk20a_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM,
|
||||||
&g->bar1_mem);
|
&l->bar1_mem);
|
||||||
if (IS_ERR(g->bar1)) {
|
if (IS_ERR(l->bar1)) {
|
||||||
nvgpu_err(g, "failed to remap gk20a bar1");
|
nvgpu_err(g, "failed to remap gk20a bar1");
|
||||||
err = PTR_ERR(g->bar1);
|
err = PTR_ERR(l->bar1);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,6 +629,10 @@ static int gk20a_init_support(struct platform_device *dev)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TEGRA_19x_GPU
|
||||||
|
t19x_init_support(g);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
#ifndef __NVGPU_COMMON_LINUX_MODULE_H__
|
#ifndef __NVGPU_COMMON_LINUX_MODULE_H__
|
||||||
#define __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 gk20a;
|
||||||
struct device;
|
struct device;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
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;
|
u32 r = start, *dest_u32 = *arg;
|
||||||
|
|
||||||
if (!g->regs) {
|
if (!l->regs) {
|
||||||
__gk20a_warn_on_no_regs();
|
__gk20a_warn_on_no_regs();
|
||||||
return;
|
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)
|
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;
|
u32 r = start, *src_u32 = *arg;
|
||||||
|
|
||||||
if (!g->regs) {
|
if (!l->regs) {
|
||||||
__gk20a_warn_on_no_regs();
|
__gk20a_warn_on_no_regs();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (words--) {
|
while (words--) {
|
||||||
writel_relaxed(*src_u32++, g->regs + r);
|
writel_relaxed(*src_u32++, l->regs + r);
|
||||||
r += sizeof(u32);
|
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)
|
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;
|
u32 r = start, repeat = **arg;
|
||||||
|
|
||||||
if (!g->regs) {
|
if (!l->regs) {
|
||||||
__gk20a_warn_on_no_regs();
|
__gk20a_warn_on_no_regs();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (words--) {
|
while (words--) {
|
||||||
writel_relaxed(repeat, g->regs + r);
|
writel_relaxed(repeat, l->regs + r);
|
||||||
r += sizeof(u32);
|
r += sizeof(u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_TEGRA_19x_GPU
|
||||||
|
#include <nvgpu/linux/os_linux_t19x.h>
|
||||||
|
#endif
|
||||||
#include "gk20a/gk20a.h"
|
#include "gk20a/gk20a.h"
|
||||||
#include "cde.h"
|
#include "cde.h"
|
||||||
|
|
||||||
@@ -85,6 +88,17 @@ struct nvgpu_os_linux {
|
|||||||
struct work_struct nonstall_fn_work;
|
struct work_struct nonstall_fn_work;
|
||||||
struct workqueue_struct *nonstall_work_queue;
|
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
|
#ifdef CONFIG_DEBUG_FS
|
||||||
struct dentry *debugfs;
|
struct dentry *debugfs;
|
||||||
struct dentry *debugfs_alias;
|
struct dentry *debugfs_alias;
|
||||||
|
|||||||
@@ -348,20 +348,21 @@ static int nvgpu_pci_init_support(struct pci_dev *pdev)
|
|||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct gk20a *g = get_gk20a(&pdev->dev);
|
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));
|
pci_resource_len(pdev, 0));
|
||||||
if (IS_ERR(g->regs)) {
|
if (IS_ERR(l->regs)) {
|
||||||
nvgpu_err(g, "failed to remap gk20a registers");
|
nvgpu_err(g, "failed to remap gk20a registers");
|
||||||
err = PTR_ERR(g->regs);
|
err = PTR_ERR(l->regs);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
g->bar1 = ioremap(pci_resource_start(pdev, 1),
|
l->bar1 = ioremap(pci_resource_start(pdev, 1),
|
||||||
pci_resource_len(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");
|
nvgpu_err(g, "failed to remap gk20a bar1");
|
||||||
err = PTR_ERR(g->bar1);
|
err = PTR_ERR(l->bar1);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ void nvgpu_pramin_access_batched(struct gk20a *g, struct nvgpu_mem *mem,
|
|||||||
* driver should be refactored to prevent this from happening, but for
|
* driver should be refactored to prevent this from happening, but for
|
||||||
* now it is ok just to ignore the writes
|
* now it is ok just to ignore the writes
|
||||||
*/
|
*/
|
||||||
if (!g->regs && nvgpu_is_enabled(g, NVGPU_DRIVER_IS_DYING))
|
if (!gk20a_io_exists(g) && nvgpu_is_enabled(g, NVGPU_DRIVER_IS_DYING))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
alloc = mem->vidmem_alloc;
|
alloc = mem->vidmem_alloc;
|
||||||
|
|||||||
@@ -65,32 +65,6 @@ void __nvgpu_check_gpu_state(struct gk20a *g)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
int gk20a_lockout_registers(struct gk20a *g)
|
|
||||||
{
|
|
||||||
g->regs = NULL;
|
|
||||||
g->bar1 = NULL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Undoes gk20a_lockout_registers().
|
|
||||||
*/
|
|
||||||
int gk20a_restore_registers(struct gk20a *g)
|
|
||||||
{
|
|
||||||
g->regs = g->regs_saved;
|
|
||||||
g->bar1 = g->bar1_saved;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __gk20a_warn_on_no_regs(void)
|
void __gk20a_warn_on_no_regs(void)
|
||||||
{
|
{
|
||||||
WARN_ONCE(1, "Attempted access to GPU regs after unmapping!");
|
WARN_ONCE(1, "Attempted access to GPU regs after unmapping!");
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ struct nvgpu_mem_sgt;
|
|||||||
|
|
||||||
#include <nvgpu/lock.h>
|
#include <nvgpu/lock.h>
|
||||||
#include <nvgpu/thread.h>
|
#include <nvgpu/thread.h>
|
||||||
|
#include <nvgpu/io.h>
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -1067,14 +1068,6 @@ struct gk20a {
|
|||||||
|
|
||||||
struct nvgpu_ref refcount;
|
struct nvgpu_ref refcount;
|
||||||
|
|
||||||
struct resource *reg_mem;
|
|
||||||
void __iomem *regs;
|
|
||||||
void __iomem *regs_saved;
|
|
||||||
|
|
||||||
struct resource *bar1_mem;
|
|
||||||
void __iomem *bar1;
|
|
||||||
void __iomem *bar1_saved;
|
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
bool gpu_reset_done;
|
bool gpu_reset_done;
|
||||||
@@ -1339,81 +1332,9 @@ enum gk20a_nonstall_ops {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* register accessors */
|
/* register accessors */
|
||||||
int gk20a_lockout_registers(struct gk20a *g);
|
|
||||||
int gk20a_restore_registers(struct gk20a *g);
|
|
||||||
|
|
||||||
void __nvgpu_check_gpu_state(struct gk20a *g);
|
void __nvgpu_check_gpu_state(struct gk20a *g);
|
||||||
void __gk20a_warn_on_no_regs(void);
|
void __gk20a_warn_on_no_regs(void);
|
||||||
|
|
||||||
static inline void gk20a_writel(struct gk20a *g, u32 r, u32 v)
|
|
||||||
{
|
|
||||||
if (unlikely(!g->regs)) {
|
|
||||||
__gk20a_warn_on_no_regs();
|
|
||||||
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x (failed)", r, v);
|
|
||||||
} else {
|
|
||||||
writel_relaxed(v, g->regs + r);
|
|
||||||
nvgpu_smp_wmb();
|
|
||||||
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x", r, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline u32 gk20a_readl(struct gk20a *g, u32 r)
|
|
||||||
{
|
|
||||||
|
|
||||||
u32 v = 0xffffffff;
|
|
||||||
|
|
||||||
if (unlikely(!g->regs)) {
|
|
||||||
__gk20a_warn_on_no_regs();
|
|
||||||
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x (failed)", r, v);
|
|
||||||
} else {
|
|
||||||
v = readl(g->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;
|
|
||||||
}
|
|
||||||
static inline void gk20a_writel_check(struct gk20a *g, u32 r, u32 v)
|
|
||||||
{
|
|
||||||
if (unlikely(!g->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, g->regs + r);
|
|
||||||
} while (readl(g->regs + r) != v);
|
|
||||||
gk20a_dbg(gpu_dbg_reg, "r=0x%x v=0x%x", r, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gk20a_bar1_writel(struct gk20a *g, u32 b, u32 v)
|
|
||||||
{
|
|
||||||
if (unlikely(!g->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, g->bar1 + b);
|
|
||||||
gk20a_dbg(gpu_dbg_reg, "b=0x%x v=0x%x", b, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 gk20a_bar1_readl(struct gk20a *g, u32 b)
|
|
||||||
{
|
|
||||||
u32 v = 0xffffffff;
|
|
||||||
|
|
||||||
if (unlikely(!g->bar1)) {
|
|
||||||
__gk20a_warn_on_no_regs();
|
|
||||||
gk20a_dbg(gpu_dbg_reg, "b=0x%x v=0x%x (failed)", b, v);
|
|
||||||
} else {
|
|
||||||
v = readl(g->bar1 + b);
|
|
||||||
gk20a_dbg(gpu_dbg_reg, "b=0x%x v=0x%x", b, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convenience */
|
/* convenience */
|
||||||
static inline struct gk20a *gk20a_from_as(struct gk20a_as *as)
|
static inline struct gk20a *gk20a_from_as(struct gk20a_as *as)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5256,8 +5256,7 @@ static inline bool is_valid_cyclestats_bar0_offset_gk20a(struct gk20a *g,
|
|||||||
is_bar0_global_offset_whitelisted_gk20a(g, offset);
|
is_bar0_global_offset_whitelisted_gk20a(g, offset);
|
||||||
/* resource size check in case there was a problem
|
/* resource size check in case there was a problem
|
||||||
* with allocating the assumed size of bar0 */
|
* with allocating the assumed size of bar0 */
|
||||||
valid = valid &&
|
valid = valid && gk20a_io_valid_reg(g, offset);
|
||||||
offset < resource_size(g->regs);
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
49
drivers/gpu/nvgpu/include/nvgpu/io.h
Normal file
49
drivers/gpu/nvgpu/include/nvgpu/io.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef __NVGPU_IO_H__
|
||||||
|
#define __NVGPU_IO_H__
|
||||||
|
|
||||||
|
#include <nvgpu/types.h>
|
||||||
|
#ifdef CONFIG_TEGRA_19x_GPU
|
||||||
|
#include <nvgpu/io_t19x.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Legacy defines - should be removed once everybody uses nvgpu_* */
|
||||||
|
#define gk20a_writel nvgpu_writel
|
||||||
|
#define gk20a_readl nvgpu_readl
|
||||||
|
#define gk20a_writel_check nvgpu_writel_check
|
||||||
|
#define gk20a_bar1_writel nvgpu_bar1_writel
|
||||||
|
#define gk20a_bar1_readl nvgpu_bar1_readl
|
||||||
|
#define gk20a_io_exists nvgpu_io_exists
|
||||||
|
#define gk20a_io_valid_reg nvgpu_io_valid_reg
|
||||||
|
|
||||||
|
struct gk20a;
|
||||||
|
|
||||||
|
void nvgpu_writel(struct gk20a *g, u32 r, u32 v);
|
||||||
|
u32 nvgpu_readl(struct gk20a *g, u32 r);
|
||||||
|
void nvgpu_writel_check(struct gk20a *g, u32 r, u32 v);
|
||||||
|
void nvgpu_bar1_writel(struct gk20a *g, u32 b, u32 v);
|
||||||
|
u32 nvgpu_bar1_readl(struct gk20a *g, u32 b);
|
||||||
|
bool nvgpu_io_exists(struct gk20a *g);
|
||||||
|
bool nvgpu_io_valid_reg(struct gk20a *g, u32 r);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -268,6 +268,7 @@ clean_up_runlist:
|
|||||||
|
|
||||||
static int vgpu_init_fifo_setup_sw(struct gk20a *g)
|
static int vgpu_init_fifo_setup_sw(struct gk20a *g)
|
||||||
{
|
{
|
||||||
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
struct fifo_gk20a *f = &g->fifo;
|
struct fifo_gk20a *f = &g->fifo;
|
||||||
struct device *d = dev_from_gk20a(g);
|
struct device *d = dev_from_gk20a(g);
|
||||||
struct vgpu_priv_data *priv = vgpu_get_priv_data(g);
|
struct vgpu_priv_data *priv = vgpu_get_priv_data(g);
|
||||||
@@ -305,7 +306,7 @@ static int vgpu_init_fifo_setup_sw(struct gk20a *g)
|
|||||||
/* if reduced BAR1 range is specified, use offset of 0
|
/* if reduced BAR1 range is specified, use offset of 0
|
||||||
* (server returns offset assuming full BAR1 range)
|
* (server returns offset assuming full BAR1 range)
|
||||||
*/
|
*/
|
||||||
if (resource_size(g->bar1_mem) ==
|
if (resource_size(l->bar1_mem) ==
|
||||||
(resource_size_t)f->userd.size)
|
(resource_size_t)f->userd.size)
|
||||||
f->userd.gpu_va = 0;
|
f->userd.gpu_va = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ static int vgpu_intr_thread(void *dev_id)
|
|||||||
|
|
||||||
static void vgpu_remove_support(struct gk20a *g)
|
static void vgpu_remove_support(struct gk20a *g)
|
||||||
{
|
{
|
||||||
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
struct vgpu_priv_data *priv =
|
struct vgpu_priv_data *priv =
|
||||||
vgpu_get_priv_data_from_dev(dev_from_gk20a(g));
|
vgpu_get_priv_data_from_dev(dev_from_gk20a(g));
|
||||||
struct tegra_vgpu_intr_msg msg;
|
struct tegra_vgpu_intr_msg msg;
|
||||||
@@ -245,18 +246,20 @@ static void vgpu_remove_support(struct gk20a *g)
|
|||||||
|
|
||||||
/* free mappings to registers, etc*/
|
/* free mappings to registers, etc*/
|
||||||
|
|
||||||
if (g->bar1) {
|
if (l->bar1) {
|
||||||
iounmap(g->bar1);
|
iounmap(l->bar1);
|
||||||
g->bar1 = NULL;
|
l->bar1 = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vgpu_init_vars(struct gk20a *g, struct gk20a_platform *platform)
|
static void vgpu_init_vars(struct gk20a *g, struct gk20a_platform *platform)
|
||||||
{
|
{
|
||||||
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
|
|
||||||
nvgpu_mutex_init(&g->poweron_lock);
|
nvgpu_mutex_init(&g->poweron_lock);
|
||||||
nvgpu_mutex_init(&g->poweroff_lock);
|
nvgpu_mutex_init(&g->poweroff_lock);
|
||||||
g->regs_saved = g->regs;
|
l->regs_saved = l->regs;
|
||||||
g->bar1_saved = g->bar1;
|
l->bar1_saved = l->bar1;
|
||||||
|
|
||||||
nvgpu_init_list_node(&g->pending_sema_waits);
|
nvgpu_init_list_node(&g->pending_sema_waits);
|
||||||
nvgpu_raw_spinlock_init(&g->pending_sema_waits_lock);
|
nvgpu_raw_spinlock_init(&g->pending_sema_waits_lock);
|
||||||
@@ -276,6 +279,7 @@ static int vgpu_init_support(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
struct gk20a *g = get_gk20a(&pdev->dev);
|
struct gk20a *g = get_gk20a(&pdev->dev);
|
||||||
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@@ -292,8 +296,8 @@ static int vgpu_init_support(struct platform_device *pdev)
|
|||||||
err = PTR_ERR(regs);
|
err = PTR_ERR(regs);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
g->bar1 = regs;
|
l->bar1 = regs;
|
||||||
g->bar1_mem = r;
|
l->bar1_mem = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvgpu_mutex_init(&g->dbg_sessions_lock);
|
nvgpu_mutex_init(&g->dbg_sessions_lock);
|
||||||
|
|||||||
Reference in New Issue
Block a user