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/nvif | |
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/nvif')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/Kbuild | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/client.c | 93 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/conn.c | 62 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/device.c | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/disp.c | 80 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/driver.c | 58 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/fifo.c | 87 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/mem.c | 103 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/mmu.c | 133 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/notify.c | 210 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/object.c | 307 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/outp.c | 62 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/timer.c | 56 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/user.c | 65 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/userc361.c | 47 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/vmm.c | 169 |
16 files changed, 1614 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvif/Kbuild b/drivers/gpu/drm/nouveau/nvif/Kbuild new file mode 100644 index 000000000..6abc4bc42 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/Kbuild @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: MIT +nvif-y := nvif/object.o +nvif-y += nvif/client.o +nvif-y += nvif/conn.o +nvif-y += nvif/device.o +nvif-y += nvif/disp.o +nvif-y += nvif/driver.o +nvif-y += nvif/fifo.o +nvif-y += nvif/mem.o +nvif-y += nvif/mmu.o +nvif-y += nvif/notify.o +nvif-y += nvif/outp.o +nvif-y += nvif/timer.o +nvif-y += nvif/vmm.o + +# Usermode classes +nvif-y += nvif/user.o +nvif-y += nvif/userc361.o diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c new file mode 100644 index 000000000..a3264a0e9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/client.c @@ -0,0 +1,93 @@ +/* + * Copyright 2013 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 <nvif/client.h> +#include <nvif/driver.h> +#include <nvif/ioctl.h> + +#include <nvif/class.h> +#include <nvif/if0000.h> + +int +nvif_client_ioctl(struct nvif_client *client, void *data, u32 size) +{ + return client->driver->ioctl(client->object.priv, data, size, NULL); +} + +int +nvif_client_suspend(struct nvif_client *client) +{ + return client->driver->suspend(client->object.priv); +} + +int +nvif_client_resume(struct nvif_client *client) +{ + return client->driver->resume(client->object.priv); +} + +void +nvif_client_dtor(struct nvif_client *client) +{ + nvif_object_dtor(&client->object); + if (client->driver) { + if (client->driver->fini) + client->driver->fini(client->object.priv); + client->driver = NULL; + } +} + +int +nvif_client_ctor(struct nvif_client *parent, const char *name, u64 device, + struct nvif_client *client) +{ + struct nvif_client_v0 args = { .device = device }; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_nop_v0 nop; + } nop = {}; + int ret; + + strncpy(args.name, name, sizeof(args.name)); + ret = nvif_object_ctor(parent != client ? &parent->object : NULL, + name ? name : "nvifClient", 0, + NVIF_CLASS_CLIENT, &args, sizeof(args), + &client->object); + if (ret) + return ret; + + client->object.client = client; + client->object.handle = ~0; + client->route = NVIF_IOCTL_V0_ROUTE_NVIF; + client->driver = parent->driver; + + if (ret == 0) { + ret = nvif_client_ioctl(client, &nop, sizeof(nop)); + client->version = nop.nop.version; + } + + if (ret) + nvif_client_dtor(client); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c new file mode 100644 index 000000000..4ce935d58 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/conn.c @@ -0,0 +1,62 @@ +/* + * Copyright 2021 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 <nvif/conn.h> +#include <nvif/disp.h> +#include <nvif/printf.h> + +#include <nvif/class.h> +#include <nvif/if0011.h> + +int +nvif_conn_hpd_status(struct nvif_conn *conn) +{ + struct nvif_conn_hpd_status_v0 args; + int ret; + + args.version = 0; + + ret = nvif_mthd(&conn->object, NVIF_CONN_V0_HPD_STATUS, &args, sizeof(args)); + NVIF_ERRON(ret, &conn->object, "[HPD_STATUS] support:%d present:%d", + args.support, args.present); + return ret ? ret : !!args.support + !!args.present; +} + +void +nvif_conn_dtor(struct nvif_conn *conn) +{ + nvif_object_dtor(&conn->object); +} + +int +nvif_conn_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_conn *conn) +{ + struct nvif_conn_v0 args; + int ret; + + args.version = 0; + args.id = id; + + ret = nvif_object_ctor(&disp->object, name ?: "nvifConn", id, NVIF_CLASS_CONN, + &args, sizeof(args), &conn->object); + NVIF_ERRON(ret, &disp->object, "[NEW conn id:%d]", id); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c new file mode 100644 index 000000000..8c3d883f3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/device.c @@ -0,0 +1,64 @@ +/* + * Copyright 2014 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 <nvif/device.h> + +u64 +nvif_device_time(struct nvif_device *device) +{ + if (!device->user.func) { + struct nv_device_time_v0 args = {}; + int ret = nvif_object_mthd(&device->object, NV_DEVICE_V0_TIME, + &args, sizeof(args)); + WARN_ON_ONCE(ret != 0); + return args.time; + } + + return device->user.func->time(&device->user); +} + +void +nvif_device_dtor(struct nvif_device *device) +{ + nvif_user_dtor(device); + kfree(device->runlist); + device->runlist = NULL; + nvif_object_dtor(&device->object); +} + +int +nvif_device_ctor(struct nvif_object *parent, const char *name, u32 handle, + s32 oclass, void *data, u32 size, struct nvif_device *device) +{ + int ret = nvif_object_ctor(parent, name ? name : "nvifDevice", handle, + oclass, data, size, &device->object); + device->runlist = NULL; + device->user.func = NULL; + if (ret == 0) { + device->info.version = 0; + ret = nvif_object_mthd(&device->object, NV_DEVICE_V0_INFO, + &device->info, sizeof(device->info)); + } + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/disp.c b/drivers/gpu/drm/nouveau/nvif/disp.c new file mode 100644 index 000000000..926b0c04b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/disp.c @@ -0,0 +1,80 @@ +/* + * 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 <nvif/disp.h> +#include <nvif/device.h> +#include <nvif/printf.h> + +#include <nvif/class.h> +#include <nvif/if0010.h> + +void +nvif_disp_dtor(struct nvif_disp *disp) +{ + nvif_object_dtor(&disp->object); +} + +int +nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct nvif_disp *disp) +{ + static const struct nvif_mclass disps[] = { + { GA102_DISP, 0 }, + { TU102_DISP, 0 }, + { GV100_DISP, 0 }, + { GP102_DISP, 0 }, + { GP100_DISP, 0 }, + { GM200_DISP, 0 }, + { GM107_DISP, 0 }, + { GK110_DISP, 0 }, + { GK104_DISP, 0 }, + { GF110_DISP, 0 }, + { GT214_DISP, 0 }, + { GT206_DISP, 0 }, + { GT200_DISP, 0 }, + { G82_DISP, 0 }, + { NV50_DISP, 0 }, + { NV04_DISP, 0 }, + {} + }; + struct nvif_disp_v0 args; + int cid, ret; + + cid = nvif_sclass(&device->object, disps, oclass); + disp->object.client = NULL; + if (cid < 0) { + NVIF_ERRON(cid, &device->object, "[NEW disp%04x] not supported", oclass); + return cid; + } + + args.version = 0; + + ret = nvif_object_ctor(&device->object, name ?: "nvifDisp", 0, + disps[cid].oclass, &args, sizeof(args), &disp->object); + NVIF_ERRON(ret, &device->object, "[NEW disp%04x]", disps[cid].oclass); + if (ret) + return ret; + + NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x", + args.conn_mask, args.outp_mask); + disp->conn_mask = args.conn_mask; + disp->outp_mask = args.outp_mask; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvif/driver.c b/drivers/gpu/drm/nouveau/nvif/driver.c new file mode 100644 index 000000000..5e00dd07a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/driver.c @@ -0,0 +1,58 @@ +/* + * Copyright 2016 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 <nvif/driver.h> +#include <nvif/client.h> + +static const struct nvif_driver * +nvif_driver[] = { +#ifdef __KERNEL__ + &nvif_driver_nvkm, +#else + &nvif_driver_drm, + &nvif_driver_lib, + &nvif_driver_null, +#endif + NULL +}; + +int +nvif_driver_init(const char *drv, const char *cfg, const char *dbg, + const char *name, u64 device, struct nvif_client *client) +{ + int ret = -EINVAL, i; + + for (i = 0; (client->driver = nvif_driver[i]); i++) { + if (!drv || !strcmp(client->driver->name, drv)) { + ret = client->driver->init(name, device, cfg, dbg, + &client->object.priv); + if (ret == 0) + break; + client->driver->fini(client->object.priv); + } + } + + if (ret == 0) + ret = nvif_client_ctor(client, name, device, client); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/fifo.c b/drivers/gpu/drm/nouveau/nvif/fifo.c new file mode 100644 index 000000000..a46328996 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/fifo.c @@ -0,0 +1,87 @@ +/* + * 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 <nvif/fifo.h> + +static int +nvif_fifo_runlists(struct nvif_device *device) +{ + struct nvif_object *object = &device->object; + struct { + struct nv_device_info_v1 m; + struct { + struct nv_device_info_v1_data runlists; + struct nv_device_info_v1_data runlist[64]; + } v; + } *a; + int ret, i; + + if (device->runlist) + return 0; + + if (!(a = kmalloc(sizeof(*a), GFP_KERNEL))) + return -ENOMEM; + a->m.version = 1; + a->m.count = sizeof(a->v) / sizeof(a->v.runlists); + a->v.runlists.mthd = NV_DEVICE_HOST_RUNLISTS; + for (i = 0; i < ARRAY_SIZE(a->v.runlist); i++) { + a->v.runlist[i].mthd = NV_DEVICE_HOST_RUNLIST_ENGINES; + a->v.runlist[i].data = i; + } + + ret = nvif_object_mthd(object, NV_DEVICE_V0_INFO, a, sizeof(*a)); + if (ret) + goto done; + + device->runlists = fls64(a->v.runlists.data); + device->runlist = kcalloc(device->runlists, sizeof(*device->runlist), + GFP_KERNEL); + if (!device->runlist) { + ret = -ENOMEM; + goto done; + } + + for (i = 0; i < device->runlists; i++) { + if (a->v.runlist[i].mthd != NV_DEVICE_INFO_INVALID) + device->runlist[i].engines = a->v.runlist[i].data; + } + +done: + kfree(a); + return ret; +} + +u64 +nvif_fifo_runlist(struct nvif_device *device, u64 engine) +{ + u64 runm = 0; + int ret, i; + + if ((ret = nvif_fifo_runlists(device))) + return runm; + + for (i = 0; i < device->runlists; i++) { + if (device->runlist[i].engines & engine) + runm |= BIT_ULL(i); + } + + return runm; +} diff --git a/drivers/gpu/drm/nouveau/nvif/mem.c b/drivers/gpu/drm/nouveau/nvif/mem.c new file mode 100644 index 000000000..0e1b7b4c2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/mem.c @@ -0,0 +1,103 @@ +/* + * 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 <nvif/mem.h> +#include <nvif/client.h> + +#include <nvif/if000a.h> + +int +nvif_mem_ctor_map(struct nvif_mmu *mmu, const char *name, u8 type, u64 size, + struct nvif_mem *mem) +{ + int ret = nvif_mem_ctor(mmu, name, mmu->mem, NVIF_MEM_MAPPABLE | type, + 0, size, NULL, 0, mem); + if (ret == 0) { + ret = nvif_object_map(&mem->object, NULL, 0); + if (ret) + nvif_mem_dtor(mem); + } + return ret; +} + +void +nvif_mem_dtor(struct nvif_mem *mem) +{ + nvif_object_dtor(&mem->object); +} + +int +nvif_mem_ctor_type(struct nvif_mmu *mmu, const char *name, s32 oclass, + int type, u8 page, u64 size, void *argv, u32 argc, + struct nvif_mem *mem) +{ + struct nvif_mem_v0 *args; + u8 stack[128]; + int ret; + + mem->object.client = NULL; + if (type < 0) + return -EINVAL; + + if (sizeof(*args) + argc > sizeof(stack)) { + if (!(args = kmalloc(sizeof(*args) + argc, GFP_KERNEL))) + return -ENOMEM; + } else { + args = (void *)stack; + } + args->version = 0; + args->type = type; + args->page = page; + args->size = size; + memcpy(args->data, argv, argc); + + ret = nvif_object_ctor(&mmu->object, name ? name : "nvifMem", 0, oclass, + args, sizeof(*args) + argc, &mem->object); + if (ret == 0) { + mem->type = mmu->type[type].type; + mem->page = args->page; + mem->addr = args->addr; + mem->size = args->size; + } + + if (args != (void *)stack) + kfree(args); + return ret; + +} + +int +nvif_mem_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass, u8 type, + u8 page, u64 size, void *argv, u32 argc, struct nvif_mem *mem) +{ + int ret = -EINVAL, i; + + mem->object.client = NULL; + + for (i = 0; ret && i < mmu->type_nr; i++) { + if ((mmu->type[i].type & type) == type) { + ret = nvif_mem_ctor_type(mmu, name, oclass, i, page, + size, argv, argc, mem); + } + } + + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/mmu.c b/drivers/gpu/drm/nouveau/nvif/mmu.c new file mode 100644 index 000000000..3709cbbc1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/mmu.c @@ -0,0 +1,133 @@ +/* + * 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 <nvif/mmu.h> + +#include <nvif/class.h> +#include <nvif/if0008.h> + +void +nvif_mmu_dtor(struct nvif_mmu *mmu) +{ + kfree(mmu->kind); + kfree(mmu->type); + kfree(mmu->heap); + nvif_object_dtor(&mmu->object); +} + +int +nvif_mmu_ctor(struct nvif_object *parent, const char *name, s32 oclass, + struct nvif_mmu *mmu) +{ + static const struct nvif_mclass mems[] = { + { NVIF_CLASS_MEM_GF100, -1 }, + { NVIF_CLASS_MEM_NV50 , -1 }, + { NVIF_CLASS_MEM_NV04 , -1 }, + {} + }; + struct nvif_mmu_v0 args; + int ret, i; + + args.version = 0; + mmu->heap = NULL; + mmu->type = NULL; + mmu->kind = NULL; + + ret = nvif_object_ctor(parent, name ? name : "nvifMmu", 0, oclass, + &args, sizeof(args), &mmu->object); + if (ret) + goto done; + + mmu->dmabits = args.dmabits; + mmu->heap_nr = args.heap_nr; + mmu->type_nr = args.type_nr; + mmu->kind_nr = args.kind_nr; + + ret = nvif_mclass(&mmu->object, mems); + if (ret < 0) + goto done; + mmu->mem = mems[ret].oclass; + + mmu->heap = kmalloc_array(mmu->heap_nr, sizeof(*mmu->heap), + GFP_KERNEL); + mmu->type = kmalloc_array(mmu->type_nr, sizeof(*mmu->type), + GFP_KERNEL); + if (ret = -ENOMEM, !mmu->heap || !mmu->type) + goto done; + + mmu->kind = kmalloc_array(mmu->kind_nr, sizeof(*mmu->kind), + GFP_KERNEL); + if (!mmu->kind && mmu->kind_nr) + goto done; + + for (i = 0; i < mmu->heap_nr; i++) { + struct nvif_mmu_heap_v0 args = { .index = i }; + + ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_HEAP, + &args, sizeof(args)); + if (ret) + goto done; + + mmu->heap[i].size = args.size; + } + + for (i = 0; i < mmu->type_nr; i++) { + struct nvif_mmu_type_v0 args = { .index = i }; + + ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_TYPE, + &args, sizeof(args)); + if (ret) + goto done; + + mmu->type[i].type = 0; + if (args.vram) mmu->type[i].type |= NVIF_MEM_VRAM; + if (args.host) mmu->type[i].type |= NVIF_MEM_HOST; + if (args.comp) mmu->type[i].type |= NVIF_MEM_COMP; + if (args.disp) mmu->type[i].type |= NVIF_MEM_DISP; + if (args.kind ) mmu->type[i].type |= NVIF_MEM_KIND; + if (args.mappable) mmu->type[i].type |= NVIF_MEM_MAPPABLE; + if (args.coherent) mmu->type[i].type |= NVIF_MEM_COHERENT; + if (args.uncached) mmu->type[i].type |= NVIF_MEM_UNCACHED; + mmu->type[i].heap = args.heap; + } + + if (mmu->kind_nr) { + struct nvif_mmu_kind_v0 *kind; + size_t argc = struct_size(kind, data, mmu->kind_nr); + + if (ret = -ENOMEM, !(kind = kmalloc(argc, GFP_KERNEL))) + goto done; + kind->version = 0; + kind->count = mmu->kind_nr; + + ret = nvif_object_mthd(&mmu->object, NVIF_MMU_V0_KIND, + kind, argc); + if (ret == 0) + memcpy(mmu->kind, kind->data, kind->count); + mmu->kind_inv = kind->kind_inv; + kfree(kind); + } + +done: + if (ret) + nvif_mmu_dtor(mmu); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c new file mode 100644 index 000000000..143c8dc68 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/notify.c @@ -0,0 +1,210 @@ +/* + * Copyright 2014 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 <nvif/client.h> +#include <nvif/driver.h> +#include <nvif/notify.h> +#include <nvif/object.h> +#include <nvif/ioctl.h> +#include <nvif/event.h> + +static inline int +nvif_notify_put_(struct nvif_notify *notify) +{ + struct nvif_object *object = notify->object; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_ntfy_put_v0 ntfy; + } args = { + .ioctl.type = NVIF_IOCTL_V0_NTFY_PUT, + .ntfy.index = notify->index, + }; + + if (atomic_inc_return(¬ify->putcnt) != 1) + return 0; + + return nvif_object_ioctl(object, &args, sizeof(args), NULL); +} + +int +nvif_notify_put(struct nvif_notify *notify) +{ + if (likely(notify->object) && + test_and_clear_bit(NVIF_NOTIFY_USER, ¬ify->flags)) { + int ret = nvif_notify_put_(notify); + if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) + flush_work(¬ify->work); + return ret; + } + return 0; +} + +static inline int +nvif_notify_get_(struct nvif_notify *notify) +{ + struct nvif_object *object = notify->object; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_ntfy_get_v0 ntfy; + } args = { + .ioctl.type = NVIF_IOCTL_V0_NTFY_GET, + .ntfy.index = notify->index, + }; + + if (atomic_dec_return(¬ify->putcnt) != 0) + return 0; + + return nvif_object_ioctl(object, &args, sizeof(args), NULL); +} + +int +nvif_notify_get(struct nvif_notify *notify) +{ + if (likely(notify->object) && + !test_and_set_bit(NVIF_NOTIFY_USER, ¬ify->flags)) + return nvif_notify_get_(notify); + return 0; +} + +static inline int +nvif_notify_func(struct nvif_notify *notify, bool keep) +{ + int ret = notify->func(notify); + if (ret == NVIF_NOTIFY_KEEP || + !test_and_clear_bit(NVIF_NOTIFY_USER, ¬ify->flags)) { + if (!keep) + atomic_dec(¬ify->putcnt); + else + nvif_notify_get_(notify); + } + return ret; +} + +static void +nvif_notify_work(struct work_struct *work) +{ + struct nvif_notify *notify = container_of(work, typeof(*notify), work); + nvif_notify_func(notify, true); +} + +int +nvif_notify(const void *header, u32 length, const void *data, u32 size) +{ + struct nvif_notify *notify = NULL; + const union { + struct nvif_notify_rep_v0 v0; + } *args = header; + int ret = NVIF_NOTIFY_DROP; + + if (length == sizeof(args->v0) && args->v0.version == 0) { + if (WARN_ON(args->v0.route)) + return NVIF_NOTIFY_DROP; + notify = (void *)(unsigned long)args->v0.token; + } + + if (!WARN_ON(notify == NULL)) { + struct nvif_client *client = notify->object->client; + if (!WARN_ON(notify->size != size)) { + atomic_inc(¬ify->putcnt); + if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) { + memcpy((void *)notify->data, data, size); + schedule_work(¬ify->work); + return NVIF_NOTIFY_DROP; + } + notify->data = data; + ret = nvif_notify_func(notify, client->driver->keep); + notify->data = NULL; + } + } + + return ret; +} + +int +nvif_notify_dtor(struct nvif_notify *notify) +{ + struct nvif_object *object = notify->object; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_ntfy_del_v0 ntfy; + } args = { + .ioctl.type = NVIF_IOCTL_V0_NTFY_DEL, + .ntfy.index = notify->index, + }; + int ret = nvif_notify_put(notify); + if (ret >= 0 && object) { + ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); + notify->object = NULL; + kfree((void *)notify->data); + } + return ret; +} + +int +nvif_notify_ctor(struct nvif_object *object, const char *name, + int (*func)(struct nvif_notify *), bool work, u8 event, + void *data, u32 size, u32 reply, struct nvif_notify *notify) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_ntfy_new_v0 ntfy; + struct nvif_notify_req_v0 req; + } *args; + int ret = -ENOMEM; + + notify->object = object; + notify->name = name ? name : "nvifNotify"; + notify->flags = 0; + atomic_set(¬ify->putcnt, 1); + notify->func = func; + notify->data = NULL; + notify->size = reply; + if (work) { + INIT_WORK(¬ify->work, nvif_notify_work); + set_bit(NVIF_NOTIFY_WORK, ¬ify->flags); + notify->data = kmalloc(notify->size, GFP_KERNEL); + if (!notify->data) + goto done; + } + + if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) + goto done; + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_NTFY_NEW; + args->ntfy.version = 0; + args->ntfy.event = event; + args->req.version = 0; + args->req.reply = notify->size; + args->req.route = 0; + args->req.token = (unsigned long)(void *)notify; + + memcpy(args->req.data, data, size); + ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); + notify->index = args->ntfy.index; + kfree(args); +done: + if (ret) + nvif_notify_dtor(notify); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c new file mode 100644 index 000000000..4d1aaee8f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -0,0 +1,307 @@ +/* + * Copyright 2014 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 <nvif/object.h> +#include <nvif/client.h> +#include <nvif/driver.h> +#include <nvif/ioctl.h> + +int +nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) +{ + struct nvif_client *client = object->client; + union { + struct nvif_ioctl_v0 v0; + } *args = data; + + if (size >= sizeof(*args) && args->v0.version == 0) { + if (object != &client->object) + args->v0.object = nvif_handle(object); + else + args->v0.object = 0; + args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; + } else + return -ENOSYS; + + return client->driver->ioctl(client->object.priv, data, size, hack); +} + +void +nvif_object_sclass_put(struct nvif_sclass **psclass) +{ + kfree(*psclass); + *psclass = NULL; +} + +int +nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_sclass_v0 sclass; + } *args = NULL; + int ret, cnt = 0, i; + u32 size; + + while (1) { + size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]); + if (!(args = kmalloc(size, GFP_KERNEL))) + return -ENOMEM; + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_SCLASS; + args->sclass.version = 0; + args->sclass.count = cnt; + + ret = nvif_object_ioctl(object, args, size, NULL); + if (ret == 0 && args->sclass.count <= cnt) + break; + cnt = args->sclass.count; + kfree(args); + if (ret != 0) + return ret; + } + + *psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL); + if (*psclass) { + for (i = 0; i < args->sclass.count; i++) { + (*psclass)[i].oclass = args->sclass.oclass[i].oclass; + (*psclass)[i].minver = args->sclass.oclass[i].minver; + (*psclass)[i].maxver = args->sclass.oclass[i].maxver; + } + ret = args->sclass.count; + } else { + ret = -ENOMEM; + } + + kfree(args); + return ret; +} + +u32 +nvif_object_rd(struct nvif_object *object, int size, u64 addr) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_rd_v0 rd; + } args = { + .ioctl.type = NVIF_IOCTL_V0_RD, + .rd.size = size, + .rd.addr = addr, + }; + int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); + if (ret) { + /*XXX: warn? */ + return 0; + } + return args.rd.data; +} + +void +nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_wr_v0 wr; + } args = { + .ioctl.type = NVIF_IOCTL_V0_WR, + .wr.size = size, + .wr.addr = addr, + .wr.data = data, + }; + int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); + if (ret) { + /*XXX: warn? */ + } +} + +int +nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_mthd_v0 mthd; + } *args; + u8 stack[128]; + int ret; + + if (sizeof(*args) + size > sizeof(stack)) { + if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) + return -ENOMEM; + } else { + args = (void *)stack; + } + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_MTHD; + args->mthd.version = 0; + args->mthd.method = mthd; + + memcpy(args->mthd.data, data, size); + ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); + memcpy(data, args->mthd.data, size); + if (args != (void *)stack) + kfree(args); + return ret; +} + +void +nvif_object_unmap_handle(struct nvif_object *object) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_unmap unmap; + } args = { + .ioctl.type = NVIF_IOCTL_V0_UNMAP, + }; + + nvif_object_ioctl(object, &args, sizeof(args), NULL); +} + +int +nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc, + u64 *handle, u64 *length) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_map_v0 map; + } *args; + u32 argn = sizeof(*args) + argc; + int ret, maptype; + + if (!(args = kzalloc(argn, GFP_KERNEL))) + return -ENOMEM; + args->ioctl.type = NVIF_IOCTL_V0_MAP; + memcpy(args->map.data, argv, argc); + + ret = nvif_object_ioctl(object, args, argn, NULL); + *handle = args->map.handle; + *length = args->map.length; + maptype = args->map.type; + kfree(args); + return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO); +} + +void +nvif_object_unmap(struct nvif_object *object) +{ + struct nvif_client *client = object->client; + if (object->map.ptr) { + if (object->map.size) { + client->driver->unmap(client, object->map.ptr, + object->map.size); + object->map.size = 0; + } + object->map.ptr = NULL; + nvif_object_unmap_handle(object); + } +} + +int +nvif_object_map(struct nvif_object *object, void *argv, u32 argc) +{ + struct nvif_client *client = object->client; + u64 handle, length; + int ret = nvif_object_map_handle(object, argv, argc, &handle, &length); + if (ret >= 0) { + if (ret) { + object->map.ptr = client->driver->map(client, + handle, + length); + if (ret = -ENOMEM, object->map.ptr) { + object->map.size = length; + return 0; + } + } else { + object->map.ptr = (void *)(unsigned long)handle; + return 0; + } + nvif_object_unmap_handle(object); + } + return ret; +} + +void +nvif_object_dtor(struct nvif_object *object) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_del del; + } args = { + .ioctl.type = NVIF_IOCTL_V0_DEL, + }; + + if (!nvif_object_constructed(object)) + return; + + nvif_object_unmap(object); + nvif_object_ioctl(object, &args, sizeof(args), NULL); + object->client = NULL; +} + +int +nvif_object_ctor(struct nvif_object *parent, const char *name, u32 handle, + s32 oclass, void *data, u32 size, struct nvif_object *object) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_new_v0 new; + } *args; + int ret = 0; + + object->client = NULL; + object->name = name ? name : "nvifObject"; + object->handle = handle; + object->oclass = oclass; + object->map.ptr = NULL; + object->map.size = 0; + + if (parent) { + if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) { + nvif_object_dtor(object); + return -ENOMEM; + } + + object->parent = parent->parent; + + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_NEW; + args->new.version = 0; + args->new.route = parent->client->route; + args->new.token = nvif_handle(object); + args->new.object = nvif_handle(object); + args->new.handle = handle; + args->new.oclass = oclass; + + memcpy(args->new.data, data, size); + ret = nvif_object_ioctl(parent, args, sizeof(*args) + size, + &object->priv); + memcpy(data, args->new.data, size); + kfree(args); + if (ret == 0) + object->client = parent->client; + } + + if (ret) + nvif_object_dtor(object); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c new file mode 100644 index 000000000..7bfe91a8d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -0,0 +1,62 @@ +/* + * Copyright 2021 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 <nvif/outp.h> +#include <nvif/disp.h> +#include <nvif/printf.h> + +#include <nvif/class.h> +#include <nvif/if0012.h> + +int +nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval) +{ + struct nvif_outp_load_detect_v0 args; + int ret; + + args.version = 0; + args.data = loadval; + + ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_LOAD_DETECT, &args, sizeof(args)); + NVIF_ERRON(ret, &outp->object, "[LOAD_DETECT data:%08x] load:%02x", args.data, args.load); + return ret < 0 ? ret : args.load; +} + +void +nvif_outp_dtor(struct nvif_outp *outp) +{ + nvif_object_dtor(&outp->object); +} + +int +nvif_outp_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_outp *outp) +{ + struct nvif_outp_v0 args; + int ret; + + args.version = 0; + args.id = id; + + ret = nvif_object_ctor(&disp->object, name ?: "nvifOutp", id, NVIF_CLASS_OUTP, + &args, sizeof(args), &outp->object); + NVIF_ERRON(ret, &disp->object, "[NEW outp id:%d]", id); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/timer.c b/drivers/gpu/drm/nouveau/nvif/timer.c new file mode 100644 index 000000000..602c1a258 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/timer.c @@ -0,0 +1,56 @@ +/* + * Copyright 2020 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 <nvif/timer.h> +#include <nvif/device.h> + +s64 +nvif_timer_wait_test(struct nvif_timer_wait *wait) +{ + u64 time = nvif_device_time(wait->device); + + if (wait->reads == 0) { + wait->time0 = time; + wait->time1 = time; + } + + if (wait->time1 == time) { + if (WARN_ON(wait->reads++ == 16)) + return -ETIMEDOUT; + } else { + wait->time1 = time; + wait->reads = 1; + } + + if (wait->time1 - wait->time0 > wait->limit) + return -ETIMEDOUT; + + return wait->time1 - wait->time0; +} + +void +nvif_timer_wait_init(struct nvif_device *device, u64 nsec, + struct nvif_timer_wait *wait) +{ + wait->device = device; + wait->limit = nsec; + wait->reads = 0; +} diff --git a/drivers/gpu/drm/nouveau/nvif/user.c b/drivers/gpu/drm/nouveau/nvif/user.c new file mode 100644 index 000000000..d89f5b67b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/user.c @@ -0,0 +1,65 @@ +/* + * 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 <nvif/user.h> +#include <nvif/device.h> + +#include <nvif/class.h> + +void +nvif_user_dtor(struct nvif_device *device) +{ + if (device->user.func) { + nvif_object_dtor(&device->user.object); + device->user.func = NULL; + } +} + +int +nvif_user_ctor(struct nvif_device *device, const char *name) +{ + struct { + s32 oclass; + int version; + const struct nvif_user_func *func; + } users[] = { + { VOLTA_USERMODE_A, -1, &nvif_userc361 }, + {} + }; + int cid, ret; + + if (device->user.func) + return 0; + + cid = nvif_mclass(&device->object, users); + if (cid < 0) + return cid; + + ret = nvif_object_ctor(&device->object, name ? name : "nvifUsermode", + 0, users[cid].oclass, NULL, 0, + &device->user.object); + if (ret) + return ret; + + nvif_object_map(&device->user.object, NULL, 0); + device->user.func = users[cid].func; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvif/userc361.c b/drivers/gpu/drm/nouveau/nvif/userc361.c new file mode 100644 index 000000000..1116f871b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/userc361.c @@ -0,0 +1,47 @@ +/* + * 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 <nvif/user.h> + +static u64 +nvif_userc361_time(struct nvif_user *user) +{ + u32 hi, lo; + + do { + hi = nvif_rd32(&user->object, 0x084); + lo = nvif_rd32(&user->object, 0x080); + } while (hi != nvif_rd32(&user->object, 0x084)); + + return ((u64)hi << 32 | lo); +} + +static void +nvif_userc361_doorbell(struct nvif_user *user, u32 token) +{ + nvif_wr32(&user->object, 0x90, token); +} + +const struct nvif_user_func +nvif_userc361 = { + .doorbell = nvif_userc361_doorbell, + .time = nvif_userc361_time, +}; diff --git a/drivers/gpu/drm/nouveau/nvif/vmm.c b/drivers/gpu/drm/nouveau/nvif/vmm.c new file mode 100644 index 000000000..6053d6dc2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/vmm.c @@ -0,0 +1,169 @@ +/* + * 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 <nvif/vmm.h> +#include <nvif/mem.h> + +#include <nvif/if000c.h> + +int +nvif_vmm_unmap(struct nvif_vmm *vmm, u64 addr) +{ + return nvif_object_mthd(&vmm->object, NVIF_VMM_V0_UNMAP, + &(struct nvif_vmm_unmap_v0) { .addr = addr }, + sizeof(struct nvif_vmm_unmap_v0)); +} + +int +nvif_vmm_map(struct nvif_vmm *vmm, u64 addr, u64 size, void *argv, u32 argc, + struct nvif_mem *mem, u64 offset) +{ + struct nvif_vmm_map_v0 *args; + u8 stack[48]; + int ret; + + if (sizeof(*args) + argc > sizeof(stack)) { + if (!(args = kmalloc(sizeof(*args) + argc, GFP_KERNEL))) + return -ENOMEM; + } else { + args = (void *)stack; + } + + args->version = 0; + args->addr = addr; + args->size = size; + args->memory = nvif_handle(&mem->object); + args->offset = offset; + memcpy(args->data, argv, argc); + + ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_MAP, + args, sizeof(*args) + argc); + if (args != (void *)stack) + kfree(args); + return ret; +} + +void +nvif_vmm_put(struct nvif_vmm *vmm, struct nvif_vma *vma) +{ + if (vma->size) { + WARN_ON(nvif_object_mthd(&vmm->object, NVIF_VMM_V0_PUT, + &(struct nvif_vmm_put_v0) { + .addr = vma->addr, + }, sizeof(struct nvif_vmm_put_v0))); + vma->size = 0; + } +} + +int +nvif_vmm_get(struct nvif_vmm *vmm, enum nvif_vmm_get type, bool sparse, + u8 page, u8 align, u64 size, struct nvif_vma *vma) +{ + struct nvif_vmm_get_v0 args; + int ret; + + args.version = vma->size = 0; + args.sparse = sparse; + args.page = page; + args.align = align; + args.size = size; + + switch (type) { + case ADDR: args.type = NVIF_VMM_GET_V0_ADDR; break; + case PTES: args.type = NVIF_VMM_GET_V0_PTES; break; + case LAZY: args.type = NVIF_VMM_GET_V0_LAZY; break; + default: + WARN_ON(1); + return -EINVAL; + } + + ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_GET, + &args, sizeof(args)); + if (ret == 0) { + vma->addr = args.addr; + vma->size = args.size; + } + return ret; +} + +void +nvif_vmm_dtor(struct nvif_vmm *vmm) +{ + kfree(vmm->page); + nvif_object_dtor(&vmm->object); +} + +int +nvif_vmm_ctor(struct nvif_mmu *mmu, const char *name, s32 oclass, bool managed, + u64 addr, u64 size, void *argv, u32 argc, struct nvif_vmm *vmm) +{ + struct nvif_vmm_v0 *args; + u32 argn = sizeof(*args) + argc; + int ret = -ENOSYS, i; + + vmm->object.client = NULL; + vmm->page = NULL; + + if (!(args = kmalloc(argn, GFP_KERNEL))) + return -ENOMEM; + args->version = 0; + args->managed = managed; + args->addr = addr; + args->size = size; + memcpy(args->data, argv, argc); + + ret = nvif_object_ctor(&mmu->object, name ? name : "nvifVmm", 0, + oclass, args, argn, &vmm->object); + if (ret) + goto done; + + vmm->start = args->addr; + vmm->limit = args->size; + + vmm->page_nr = args->page_nr; + vmm->page = kmalloc_array(vmm->page_nr, sizeof(*vmm->page), + GFP_KERNEL); + if (!vmm->page) { + ret = -ENOMEM; + goto done; + } + + for (i = 0; i < vmm->page_nr; i++) { + struct nvif_vmm_page_v0 args = { .index = i }; + + ret = nvif_object_mthd(&vmm->object, NVIF_VMM_V0_PAGE, + &args, sizeof(args)); + if (ret) + break; + + vmm->page[i].shift = args.shift; + vmm->page[i].sparse = args.sparse; + vmm->page[i].vram = args.vram; + vmm->page[i].host = args.host; + vmm->page[i].comp = args.comp; + } + +done: + if (ret) + nvif_vmm_dtor(vmm); + kfree(args); + return ret; +} |