diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
commit | 2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch) | |
tree | 848558de17fb3008cdf4d861b01ac7781903ce39 /drivers/gpu/drm/nouveau/nvkm/subdev/bar | |
parent | Initial commit. (diff) | |
download | linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.tar.xz linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.zip |
Adding upstream version 6.1.76.upstream/6.1.76
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/bar')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c | 142 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c | 63 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 196 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/gm107.c | 66 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/gm20b.c | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 255 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu102.c | 99 |
12 files changed, 1004 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild new file mode 100644 index 000000000..8faee3317 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT +nvkm-y += nvkm/subdev/bar/base.o +nvkm-y += nvkm/subdev/bar/nv50.o +nvkm-y += nvkm/subdev/bar/g84.o +nvkm-y += nvkm/subdev/bar/gf100.o +nvkm-y += nvkm/subdev/bar/gk20a.o +nvkm-y += nvkm/subdev/bar/gm107.o +nvkm-y += nvkm/subdev/bar/gm20b.o +nvkm-y += nvkm/subdev/bar/tu102.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c new file mode 100644 index 000000000..d017a1b5e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -0,0 +1,142 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs + */ +#include "priv.h" + +void +nvkm_bar_flush(struct nvkm_bar *bar) +{ + if (bar && bar->func->flush) + bar->func->flush(bar); +} + +struct nvkm_vmm * +nvkm_bar_bar1_vmm(struct nvkm_device *device) +{ + return device->bar->func->bar1.vmm(device->bar); +} + +void +nvkm_bar_bar1_reset(struct nvkm_device *device) +{ + struct nvkm_bar *bar = device->bar; + if (bar) { + bar->func->bar1.init(bar); + bar->func->bar1.wait(bar); + } +} + +struct nvkm_vmm * +nvkm_bar_bar2_vmm(struct nvkm_device *device) +{ + /* Denies access to BAR2 when it's not initialised, used by INSTMEM + * to know when object access needs to go through the BAR0 window. + */ + struct nvkm_bar *bar = device->bar; + if (bar && bar->bar2) + return bar->func->bar2.vmm(bar); + return NULL; +} + +void +nvkm_bar_bar2_reset(struct nvkm_device *device) +{ + struct nvkm_bar *bar = device->bar; + if (bar && bar->bar2) { + bar->func->bar2.init(bar); + bar->func->bar2.wait(bar); + } +} + +void +nvkm_bar_bar2_fini(struct nvkm_device *device) +{ + struct nvkm_bar *bar = device->bar; + if (bar && bar->bar2) { + bar->func->bar2.fini(bar); + bar->bar2 = false; + } +} + +void +nvkm_bar_bar2_init(struct nvkm_device *device) +{ + struct nvkm_bar *bar = device->bar; + if (bar && bar->subdev.oneinit && !bar->bar2 && bar->func->bar2.init) { + bar->func->bar2.init(bar); + bar->func->bar2.wait(bar); + bar->bar2 = true; + } +} + +static int +nvkm_bar_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_bar *bar = nvkm_bar(subdev); + if (bar->func->bar1.fini) + bar->func->bar1.fini(bar); + return 0; +} + +static int +nvkm_bar_init(struct nvkm_subdev *subdev) +{ + struct nvkm_bar *bar = nvkm_bar(subdev); + bar->func->bar1.init(bar); + bar->func->bar1.wait(bar); + if (bar->func->init) + bar->func->init(bar); + return 0; +} + +static int +nvkm_bar_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_bar *bar = nvkm_bar(subdev); + return bar->func->oneinit(bar); +} + +static void * +nvkm_bar_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_bar *bar = nvkm_bar(subdev); + nvkm_bar_bar2_fini(subdev->device); + return bar->func->dtor(bar); +} + +static const struct nvkm_subdev_func +nvkm_bar = { + .dtor = nvkm_bar_dtor, + .oneinit = nvkm_bar_oneinit, + .init = nvkm_bar_init, + .fini = nvkm_bar_fini, +}; + +void +nvkm_bar_ctor(const struct nvkm_bar_func *func, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_bar *bar) +{ + nvkm_subdev_ctor(&nvkm_bar, device, type, inst, &bar->subdev); + bar->func = func; + spin_lock_init(&bar->lock); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c new file mode 100644 index 000000000..77a41bcf8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c @@ -0,0 +1,63 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#include "nv50.h" + +#include <subdev/timer.h> + +void +g84_bar_flush(struct nvkm_bar *bar) +{ + struct nvkm_device *device = bar->subdev.device; + unsigned long flags; + spin_lock_irqsave(&bar->lock, flags); + nvkm_wr32(device, 0x070000, 0x00000001); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x070000) & 0x00000002)) + break; + ); + spin_unlock_irqrestore(&bar->lock, flags); +} + +static const struct nvkm_bar_func +g84_bar_func = { + .dtor = nv50_bar_dtor, + .oneinit = nv50_bar_oneinit, + .init = nv50_bar_init, + .bar1.init = nv50_bar_bar1_init, + .bar1.fini = nv50_bar_bar1_fini, + .bar1.wait = nv50_bar_bar1_wait, + .bar1.vmm = nv50_bar_bar1_vmm, + .bar2.init = nv50_bar_bar2_init, + .bar2.fini = nv50_bar_bar2_fini, + .bar2.wait = nv50_bar_bar1_wait, + .bar2.vmm = nv50_bar_bar2_vmm, + .flush = g84_bar_flush, +}; + +int +g84_bar_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_bar **pbar) +{ + return nv50_bar_new_(&g84_bar_func, device, type, inst, 0x200, pbar); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c new file mode 100644 index 000000000..51070b7dd --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -0,0 +1,196 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs + */ +#include "gf100.h" + +#include <core/memory.h> +#include <core/option.h> +#include <subdev/fb.h> +#include <subdev/mmu.h> + +struct nvkm_vmm * +gf100_bar_bar1_vmm(struct nvkm_bar *base) +{ + return gf100_bar(base)->bar[1].vmm; +} + +void +gf100_bar_bar1_wait(struct nvkm_bar *base) +{ + /* NFI why it's twice. */ + nvkm_bar_flush(base); + nvkm_bar_flush(base); +} + +void +gf100_bar_bar1_fini(struct nvkm_bar *bar) +{ + nvkm_mask(bar->subdev.device, 0x001704, 0x80000000, 0x00000000); +} + +void +gf100_bar_bar1_init(struct nvkm_bar *base) +{ + struct nvkm_device *device = base->subdev.device; + struct gf100_bar *bar = gf100_bar(base); + const u32 addr = nvkm_memory_addr(bar->bar[1].inst) >> 12; + nvkm_wr32(device, 0x001704, 0x80000000 | addr); +} + +struct nvkm_vmm * +gf100_bar_bar2_vmm(struct nvkm_bar *base) +{ + return gf100_bar(base)->bar[0].vmm; +} + +void +gf100_bar_bar2_fini(struct nvkm_bar *bar) +{ + nvkm_mask(bar->subdev.device, 0x001714, 0x80000000, 0x00000000); +} + +void +gf100_bar_bar2_init(struct nvkm_bar *base) +{ + struct nvkm_device *device = base->subdev.device; + struct gf100_bar *bar = gf100_bar(base); + u32 addr = nvkm_memory_addr(bar->bar[0].inst) >> 12; + if (bar->bar2_halve) + addr |= 0x40000000; + nvkm_wr32(device, 0x001714, 0x80000000 | addr); +} + +static int +gf100_bar_oneinit_bar(struct gf100_bar *bar, struct gf100_barN *bar_vm, + struct lock_class_key *key, int bar_nr) +{ + struct nvkm_device *device = bar->base.subdev.device; + resource_size_t bar_len; + int ret; + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0, false, + &bar_vm->inst); + if (ret) + return ret; + + bar_len = device->func->resource_size(device, bar_nr); + if (!bar_len) + return -ENOMEM; + if (bar_nr == 3 && bar->bar2_halve) + bar_len >>= 1; + + ret = nvkm_vmm_new(device, 0, bar_len, NULL, 0, key, + (bar_nr == 3) ? "bar2" : "bar1", &bar_vm->vmm); + if (ret) + return ret; + + atomic_inc(&bar_vm->vmm->engref[NVKM_SUBDEV_BAR]); + bar_vm->vmm->debug = bar->base.subdev.debug; + + /* + * Bootstrap page table lookup. + */ + if (bar_nr == 3) { + ret = nvkm_vmm_boot(bar_vm->vmm); + if (ret) + return ret; + } + + return nvkm_vmm_join(bar_vm->vmm, bar_vm->inst); +} + +int +gf100_bar_oneinit(struct nvkm_bar *base) +{ + static struct lock_class_key bar1_lock; + static struct lock_class_key bar2_lock; + struct gf100_bar *bar = gf100_bar(base); + int ret; + + /* BAR2 */ + if (bar->base.func->bar2.init) { + ret = gf100_bar_oneinit_bar(bar, &bar->bar[0], &bar2_lock, 3); + if (ret) + return ret; + + bar->base.subdev.oneinit = true; + nvkm_bar_bar2_init(bar->base.subdev.device); + } + + /* BAR1 */ + ret = gf100_bar_oneinit_bar(bar, &bar->bar[1], &bar1_lock, 1); + if (ret) + return ret; + + return 0; +} + +void * +gf100_bar_dtor(struct nvkm_bar *base) +{ + struct gf100_bar *bar = gf100_bar(base); + + nvkm_vmm_part(bar->bar[1].vmm, bar->bar[1].inst); + nvkm_vmm_unref(&bar->bar[1].vmm); + nvkm_memory_unref(&bar->bar[1].inst); + + nvkm_vmm_part(bar->bar[0].vmm, bar->bar[0].inst); + nvkm_vmm_unref(&bar->bar[0].vmm); + nvkm_memory_unref(&bar->bar[0].inst); + return bar; +} + +int +gf100_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, struct nvkm_bar **pbar) +{ + struct gf100_bar *bar; + if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL))) + return -ENOMEM; + nvkm_bar_ctor(func, device, type, inst, &bar->base); + bar->bar2_halve = nvkm_boolopt(device->cfgopt, "NvBar2Halve", false); + *pbar = &bar->base; + return 0; +} + +static const struct nvkm_bar_func +gf100_bar_func = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .bar1.init = gf100_bar_bar1_init, + .bar1.fini = gf100_bar_bar1_fini, + .bar1.wait = gf100_bar_bar1_wait, + .bar1.vmm = gf100_bar_bar1_vmm, + .bar2.init = gf100_bar_bar2_init, + .bar2.fini = gf100_bar_bar2_fini, + .bar2.wait = gf100_bar_bar1_wait, + .bar2.vmm = gf100_bar_bar2_vmm, + .flush = g84_bar_flush, +}; + +int +gf100_bar_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_bar **pbar) +{ + return gf100_bar_new_(&gf100_bar_func, device, type, inst, pbar); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h new file mode 100644 index 000000000..328a68b41 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __GF100_BAR_H__ +#define __GF100_BAR_H__ +#define gf100_bar(p) container_of((p), struct gf100_bar, base) +#include "priv.h" + +struct gf100_barN { + struct nvkm_memory *inst; + struct nvkm_vmm *vmm; +}; + +struct gf100_bar { + struct nvkm_bar base; + bool bar2_halve; + struct gf100_barN bar[2]; +}; + +int gf100_bar_new_(const struct nvkm_bar_func *, struct nvkm_device *, enum nvkm_subdev_type, + int, struct nvkm_bar **); +void *gf100_bar_dtor(struct nvkm_bar *); +int gf100_bar_oneinit(struct nvkm_bar *); +void gf100_bar_bar1_init(struct nvkm_bar *); +void gf100_bar_bar1_wait(struct nvkm_bar *); +struct nvkm_vmm *gf100_bar_bar1_vmm(struct nvkm_bar *); +void gf100_bar_bar2_init(struct nvkm_bar *); +struct nvkm_vmm *gf100_bar_bar2_vmm(struct nvkm_bar *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c new file mode 100644 index 000000000..eead8ab88 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, 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. + */ +#include "gf100.h" + +static const struct nvkm_bar_func +gk20a_bar_func = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .bar1.init = gf100_bar_bar1_init, + .bar1.wait = gf100_bar_bar1_wait, + .bar1.vmm = gf100_bar_bar1_vmm, + .flush = g84_bar_flush, +}; + +int +gk20a_bar_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_bar **pbar) +{ + int ret = gf100_bar_new_(&gk20a_bar_func, device, type, inst, pbar); + if (ret == 0) + (*pbar)->iomap_uncached = true; + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gm107.c new file mode 100644 index 000000000..da95307a7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gm107.c @@ -0,0 +1,66 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ +#include "gf100.h" + +#include <subdev/timer.h> + +void +gm107_bar_bar1_wait(struct nvkm_bar *bar) +{ + struct nvkm_device *device = bar->subdev.device; + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x001710) & 0x00000003)) + break; + ); +} + +static void +gm107_bar_bar2_wait(struct nvkm_bar *bar) +{ + struct nvkm_device *device = bar->subdev.device; + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x001710) & 0x0000000c)) + break; + ); +} + +static const struct nvkm_bar_func +gm107_bar_func = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .bar1.init = gf100_bar_bar1_init, + .bar1.fini = gf100_bar_bar1_fini, + .bar1.wait = gm107_bar_bar1_wait, + .bar1.vmm = gf100_bar_bar1_vmm, + .bar2.init = gf100_bar_bar2_init, + .bar2.fini = gf100_bar_bar2_fini, + .bar2.wait = gm107_bar_bar2_wait, + .bar2.vmm = gf100_bar_bar2_vmm, + .flush = g84_bar_flush, +}; + +int +gm107_bar_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_bar **pbar) +{ + return gf100_bar_new_(&gm107_bar_func, device, type, inst, pbar); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gm20b.c new file mode 100644 index 000000000..4acdb4fb0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gm20b.c @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ +#include "gf100.h" + +static const struct nvkm_bar_func +gm20b_bar_func = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .bar1.init = gf100_bar_bar1_init, + .bar1.wait = gm107_bar_bar1_wait, + .bar1.vmm = gf100_bar_bar1_vmm, + .flush = g84_bar_flush, +}; + +int +gm20b_bar_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_bar **pbar) +{ + int ret = gf100_bar_new_(&gm20b_bar_func, device, type, inst, pbar); + if (ret == 0) + (*pbar)->iomap_uncached = true; + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c new file mode 100644 index 000000000..27d8a1be4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -0,0 +1,255 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs + */ +#include "nv50.h" + +#include <core/gpuobj.h> +#include <subdev/fb.h> +#include <subdev/mmu.h> +#include <subdev/timer.h> + +static void +nv50_bar_flush(struct nvkm_bar *base) +{ + struct nv50_bar *bar = nv50_bar(base); + struct nvkm_device *device = bar->base.subdev.device; + unsigned long flags; + spin_lock_irqsave(&bar->base.lock, flags); + nvkm_wr32(device, 0x00330c, 0x00000001); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x00330c) & 0x00000002)) + break; + ); + spin_unlock_irqrestore(&bar->base.lock, flags); +} + +struct nvkm_vmm * +nv50_bar_bar1_vmm(struct nvkm_bar *base) +{ + return nv50_bar(base)->bar1_vmm; +} + +void +nv50_bar_bar1_wait(struct nvkm_bar *base) +{ + nvkm_bar_flush(base); +} + +void +nv50_bar_bar1_fini(struct nvkm_bar *bar) +{ + nvkm_wr32(bar->subdev.device, 0x001708, 0x00000000); +} + +void +nv50_bar_bar1_init(struct nvkm_bar *base) +{ + struct nvkm_device *device = base->subdev.device; + struct nv50_bar *bar = nv50_bar(base); + nvkm_wr32(device, 0x001708, 0x80000000 | bar->bar1->node->offset >> 4); +} + +struct nvkm_vmm * +nv50_bar_bar2_vmm(struct nvkm_bar *base) +{ + return nv50_bar(base)->bar2_vmm; +} + +void +nv50_bar_bar2_fini(struct nvkm_bar *bar) +{ + nvkm_wr32(bar->subdev.device, 0x00170c, 0x00000000); +} + +void +nv50_bar_bar2_init(struct nvkm_bar *base) +{ + struct nvkm_device *device = base->subdev.device; + struct nv50_bar *bar = nv50_bar(base); + nvkm_wr32(device, 0x001704, 0x00000000 | bar->mem->addr >> 12); + nvkm_wr32(device, 0x001704, 0x40000000 | bar->mem->addr >> 12); + nvkm_wr32(device, 0x00170c, 0x80000000 | bar->bar2->node->offset >> 4); +} + +void +nv50_bar_init(struct nvkm_bar *base) +{ + struct nv50_bar *bar = nv50_bar(base); + struct nvkm_device *device = bar->base.subdev.device; + int i; + + for (i = 0; i < 8; i++) + nvkm_wr32(device, 0x001900 + (i * 4), 0x00000000); +} + +int +nv50_bar_oneinit(struct nvkm_bar *base) +{ + struct nv50_bar *bar = nv50_bar(base); + struct nvkm_device *device = bar->base.subdev.device; + static struct lock_class_key bar1_lock; + static struct lock_class_key bar2_lock; + u64 start, limit, size; + int ret; + + ret = nvkm_gpuobj_new(device, 0x20000, 0, false, NULL, &bar->mem); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, bar->pgd_addr, 0, false, bar->mem, + &bar->pad); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, bar->mem, &bar->pgd); + if (ret) + return ret; + + /* BAR2 */ + start = 0x0100000000ULL; + size = device->func->resource_size(device, 3); + if (!size) + return -ENOMEM; + limit = start + size; + + ret = nvkm_vmm_new(device, start, limit-- - start, NULL, 0, + &bar2_lock, "bar2", &bar->bar2_vmm); + if (ret) + return ret; + + atomic_inc(&bar->bar2_vmm->engref[NVKM_SUBDEV_BAR]); + bar->bar2_vmm->debug = bar->base.subdev.debug; + + ret = nvkm_vmm_boot(bar->bar2_vmm); + if (ret) + return ret; + + ret = nvkm_vmm_join(bar->bar2_vmm, bar->mem->memory); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 24, 16, false, bar->mem, &bar->bar2); + if (ret) + return ret; + + nvkm_kmap(bar->bar2); + nvkm_wo32(bar->bar2, 0x00, 0x7fc00000); + nvkm_wo32(bar->bar2, 0x04, lower_32_bits(limit)); + nvkm_wo32(bar->bar2, 0x08, lower_32_bits(start)); + nvkm_wo32(bar->bar2, 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(bar->bar2, 0x10, 0x00000000); + nvkm_wo32(bar->bar2, 0x14, 0x00000000); + nvkm_done(bar->bar2); + + bar->base.subdev.oneinit = true; + nvkm_bar_bar2_init(device); + + /* BAR1 */ + start = 0x0000000000ULL; + size = device->func->resource_size(device, 1); + if (!size) + return -ENOMEM; + limit = start + size; + + ret = nvkm_vmm_new(device, start, limit-- - start, NULL, 0, + &bar1_lock, "bar1", &bar->bar1_vmm); + if (ret) + return ret; + + atomic_inc(&bar->bar1_vmm->engref[NVKM_SUBDEV_BAR]); + bar->bar1_vmm->debug = bar->base.subdev.debug; + + ret = nvkm_vmm_join(bar->bar1_vmm, bar->mem->memory); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 24, 16, false, bar->mem, &bar->bar1); + if (ret) + return ret; + + nvkm_kmap(bar->bar1); + nvkm_wo32(bar->bar1, 0x00, 0x7fc00000); + nvkm_wo32(bar->bar1, 0x04, lower_32_bits(limit)); + nvkm_wo32(bar->bar1, 0x08, lower_32_bits(start)); + nvkm_wo32(bar->bar1, 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(bar->bar1, 0x10, 0x00000000); + nvkm_wo32(bar->bar1, 0x14, 0x00000000); + nvkm_done(bar->bar1); + return 0; +} + +void * +nv50_bar_dtor(struct nvkm_bar *base) +{ + struct nv50_bar *bar = nv50_bar(base); + if (bar->mem) { + nvkm_gpuobj_del(&bar->bar1); + nvkm_vmm_part(bar->bar1_vmm, bar->mem->memory); + nvkm_vmm_unref(&bar->bar1_vmm); + nvkm_gpuobj_del(&bar->bar2); + nvkm_vmm_part(bar->bar2_vmm, bar->mem->memory); + nvkm_vmm_unref(&bar->bar2_vmm); + nvkm_gpuobj_del(&bar->pgd); + nvkm_gpuobj_del(&bar->pad); + nvkm_gpuobj_del(&bar->mem); + } + return bar; +} + +int +nv50_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device, + enum nvkm_subdev_type type, int inst, u32 pgd_addr, struct nvkm_bar **pbar) +{ + struct nv50_bar *bar; + if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL))) + return -ENOMEM; + nvkm_bar_ctor(func, device, type, inst, &bar->base); + bar->pgd_addr = pgd_addr; + *pbar = &bar->base; + return 0; +} + +static const struct nvkm_bar_func +nv50_bar_func = { + .dtor = nv50_bar_dtor, + .oneinit = nv50_bar_oneinit, + .init = nv50_bar_init, + .bar1.init = nv50_bar_bar1_init, + .bar1.fini = nv50_bar_bar1_fini, + .bar1.wait = nv50_bar_bar1_wait, + .bar1.vmm = nv50_bar_bar1_vmm, + .bar2.init = nv50_bar_bar2_init, + .bar2.fini = nv50_bar_bar2_fini, + .bar2.wait = nv50_bar_bar1_wait, + .bar2.vmm = nv50_bar_bar2_vmm, + .flush = nv50_bar_flush, +}; + +int +nv50_bar_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_bar **pbar) +{ + return nv50_bar_new_(&nv50_bar_func, device, type, inst, 0x1400, pbar); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h new file mode 100644 index 000000000..dedee9394 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NV50_BAR_H__ +#define __NV50_BAR_H__ +#define nv50_bar(p) container_of((p), struct nv50_bar, base) +#include "priv.h" + +struct nv50_bar { + struct nvkm_bar base; + u32 pgd_addr; + struct nvkm_gpuobj *mem; + struct nvkm_gpuobj *pad; + struct nvkm_gpuobj *pgd; + struct nvkm_vmm *bar1_vmm; + struct nvkm_gpuobj *bar1; + struct nvkm_vmm *bar2_vmm; + struct nvkm_gpuobj *bar2; +}; + +int nv50_bar_new_(const struct nvkm_bar_func *, struct nvkm_device *, enum nvkm_subdev_type, + int, u32 pgd_addr, struct nvkm_bar **); +void *nv50_bar_dtor(struct nvkm_bar *); +int nv50_bar_oneinit(struct nvkm_bar *); +void nv50_bar_init(struct nvkm_bar *); +void nv50_bar_bar1_init(struct nvkm_bar *); +void nv50_bar_bar1_wait(struct nvkm_bar *); +struct nvkm_vmm *nv50_bar_bar1_vmm(struct nvkm_bar *); +void nv50_bar_bar2_init(struct nvkm_bar *); +struct nvkm_vmm *nv50_bar_bar2_vmm(struct nvkm_bar *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h new file mode 100644 index 000000000..daebfc991 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVKM_BAR_PRIV_H__ +#define __NVKM_BAR_PRIV_H__ +#define nvkm_bar(p) container_of((p), struct nvkm_bar, subdev) +#include <subdev/bar.h> + +void nvkm_bar_ctor(const struct nvkm_bar_func *, struct nvkm_device *, + enum nvkm_subdev_type, int, struct nvkm_bar *); + +struct nvkm_bar_func { + void *(*dtor)(struct nvkm_bar *); + int (*oneinit)(struct nvkm_bar *); + void (*init)(struct nvkm_bar *); + + struct { + void (*init)(struct nvkm_bar *); + void (*fini)(struct nvkm_bar *); + void (*wait)(struct nvkm_bar *); + struct nvkm_vmm *(*vmm)(struct nvkm_bar *); + } bar1, bar2; + + void (*flush)(struct nvkm_bar *); +}; + +void nv50_bar_bar1_fini(struct nvkm_bar *); +void nv50_bar_bar2_fini(struct nvkm_bar *); + +void g84_bar_flush(struct nvkm_bar *); + +void gf100_bar_bar1_fini(struct nvkm_bar *); +void gf100_bar_bar2_fini(struct nvkm_bar *); + +void gm107_bar_bar1_wait(struct nvkm_bar *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu102.c new file mode 100644 index 000000000..c25ab407b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/tu102.c @@ -0,0 +1,99 @@ +/* + * Copyright 2018 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ +#include "gf100.h" + +#include <core/memory.h> +#include <subdev/timer.h> + +static void +tu102_bar_bar2_wait(struct nvkm_bar *bar) +{ + struct nvkm_device *device = bar->subdev.device; + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0xb80f50) & 0x0000000c)) + break; + ); +} + +static void +tu102_bar_bar2_fini(struct nvkm_bar *bar) +{ + nvkm_mask(bar->subdev.device, 0xb80f48, 0x80000000, 0x00000000); +} + +static void +tu102_bar_bar2_init(struct nvkm_bar *base) +{ + struct nvkm_device *device = base->subdev.device; + struct gf100_bar *bar = gf100_bar(base); + u32 addr = nvkm_memory_addr(bar->bar[0].inst) >> 12; + if (bar->bar2_halve) + addr |= 0x40000000; + nvkm_wr32(device, 0xb80f48, 0x80000000 | addr); +} + +static void +tu102_bar_bar1_wait(struct nvkm_bar *bar) +{ + struct nvkm_device *device = bar->subdev.device; + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0xb80f50) & 0x00000003)) + break; + ); +} + +static void +tu102_bar_bar1_fini(struct nvkm_bar *bar) +{ + nvkm_mask(bar->subdev.device, 0xb80f40, 0x80000000, 0x00000000); +} + +static void +tu102_bar_bar1_init(struct nvkm_bar *base) +{ + struct nvkm_device *device = base->subdev.device; + struct gf100_bar *bar = gf100_bar(base); + const u32 addr = nvkm_memory_addr(bar->bar[1].inst) >> 12; + nvkm_wr32(device, 0xb80f40, 0x80000000 | addr); +} + +static const struct nvkm_bar_func +tu102_bar = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .bar1.init = tu102_bar_bar1_init, + .bar1.fini = tu102_bar_bar1_fini, + .bar1.wait = tu102_bar_bar1_wait, + .bar1.vmm = gf100_bar_bar1_vmm, + .bar2.init = tu102_bar_bar2_init, + .bar2.fini = tu102_bar_bar2_fini, + .bar2.wait = tu102_bar_bar2_wait, + .bar2.vmm = gf100_bar_bar2_vmm, + .flush = g84_bar_flush, +}; + +int +tu102_bar_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_bar **pbar) +{ + return gf100_bar_new_(&tu102_bar, device, type, inst, pbar); +} |