From f1fcc4ed7b234391e1aec6b7f3e1001e9729bdfe Mon Sep 17 00:00:00 2001 From: Jérôme Glisse Date: Thu, 10 Aug 2017 16:25:21 -0400 Subject: drm/nouveau/compote: add GPU page fault handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Glisse --- drivers/gpu/drm/nouveau/compote/Kbuild | 1 + drivers/gpu/drm/nouveau/compote/compote-driver.c | 7 + drivers/gpu/drm/nouveau/compote/compote-pfault.c | 172 +++++++++++++++++++++++ drivers/gpu/drm/nouveau/compote/compote.h | 5 + 4 files changed, 185 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/compote/compote-pfault.c diff --git a/drivers/gpu/drm/nouveau/compote/Kbuild b/drivers/gpu/drm/nouveau/compote/Kbuild index 76de5f87299b..c210eb8f60ea 100644 --- a/drivers/gpu/drm/nouveau/compote/Kbuild +++ b/drivers/gpu/drm/nouveau/compote/Kbuild @@ -3,4 +3,5 @@ compote-y := compote/compote-driver.o compote-y += compote/compote-memory.o compote-y += compote/compote-channel.o compote-y += compote/compote-hmm.o +compote-y += compote/compote-pfault.o endif diff --git a/drivers/gpu/drm/nouveau/compote/compote-driver.c b/drivers/gpu/drm/nouveau/compote/compote-driver.c index 9ffd966546b9..8ed833683772 100644 --- a/drivers/gpu/drm/nouveau/compote/compote-driver.c +++ b/drivers/gpu/drm/nouveau/compote/compote-driver.c @@ -132,6 +132,10 @@ static int compote_open(struct inode *inode, struct file *file) if (ret) goto error_vm; + ret = compote_file_pfault_init(cfile); + if (ret) + goto error_pfault; + /* share address_space across all char-devs of a single device */ file->f_mapping = cdevice->nvdrm->dev->anon_inode->i_mapping; @@ -141,6 +145,8 @@ static int compote_open(struct inode *inode, struct file *file) file->private_data = cfile; return 0; +error_pfault: + compote_file_hmm_fini(cfile); error_vm: compote_client_fini(&cfile->nvclient); error: @@ -167,6 +173,7 @@ static int compote_close(struct inode *inode, struct file *file) compote_channel_unref(channel); } + compote_file_pfault_fini(cfile); compote_file_hmm_fini(cfile); compote_client_fini(&cfile->nvclient); diff --git a/drivers/gpu/drm/nouveau/compote/compote-pfault.c b/drivers/gpu/drm/nouveau/compote/compote-pfault.c new file mode 100644 index 000000000000..f46c13fad44d --- /dev/null +++ b/drivers/gpu/drm/nouveau/compote/compote-pfault.c @@ -0,0 +1,172 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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. + * + * Authors: Jérôme Glisse + */ +#include +#include +#include +#include +#include +#include +#include "compote.h" + +#include +#include +#include + +#include "nouveau_ttm.h" +#include "nouveau_usif.h" +#include "nouveau_abi16.h" + +struct compote_pfault { + uint64_t inst; + uint64_t addr; + uint64_t time; + uint32_t rsvd; + uint32_t info; +}; + +static inline uint32_t compote_pfault_valid(const struct compote_pfault *pfault) +{ + return (pfault->info & 0x80000000) >> 31; +} + +static inline uint32_t compote_pfault_gpc(const struct compote_pfault *pfault) +{ + return (pfault->info & 0x1f000000) >> 24; +} + +static inline uint32_t compote_pfault_isgpc(const struct compote_pfault *pfault) +{ + return (pfault->info & 0x00100000) >> 20; +} + +static inline uint32_t compote_pfault_access(const struct compote_pfault *pfault) +{ + return (pfault->info & 0x00070000) >> 16; +} + +static inline uint32_t compote_pfault_client(const struct compote_pfault *pfault) +{ + return (pfault->info & 0x00007f00) >> 8; +} + +static inline uint32_t compote_pfault_fault(const struct compote_pfault *pfault) +{ + return (pfault->info & 0x0000001f) >> 0; +} + +static inline void compote_file_pfault_read(struct compote_file *cfile, + struct compote_pfault *pfault, + uint32_t index) +{ + index *= 32; + pfault->inst = nvif_rd32(&cfile->nvpfault_buffer, index + 0x00); + pfault->inst |= ((uint64_t)nvif_rd32(&cfile->nvpfault_buffer, index + 0x04)) << 32; + pfault->addr = nvif_rd32(&cfile->nvpfault_buffer, index + 0x08); + pfault->addr |= ((uint64_t)nvif_rd32(&cfile->nvpfault_buffer, index + 0x0c)) << 32; + pfault->time = nvif_rd32(&cfile->nvpfault_buffer, index + 0x10); + pfault->time |= ((uint64_t)nvif_rd32(&cfile->nvpfault_buffer, index + 0x14)) << 32; + pfault->rsvd = nvif_rd32(&cfile->nvpfault_buffer, index + 0x18); + pfault->info = nvif_rd32(&cfile->nvpfault_buffer, index + 0x1c); +} + +static int compote_pfault_handler(struct compote_file *cfile, + const struct compote_pfault *pfault) +{ + return -EINVAL; +} + +static int compote_file_pfault_process(struct nvif_notify *notify) +{ + struct compote_file *cfile; + struct nvif_device *device; + uint32_t get, put; + + cfile = container_of(notify, struct compote_file, nvpfault_notifier); + device = &cfile->nvclient.device; + + get = nvif_rd32(&device->object, 0x002a7c); + put = nvif_rd32(&device->object, 0x002a80); + + for (; get != put; get++) { + struct compote_pfault pfault; + int ret; + + compote_file_pfault_read(cfile, &pfault, get); + + nvif_wr32(&device->object, 0x002a7c, get + 1); + if (!compote_pfault_valid(&pfault)) + continue; + + nvif_mask(&cfile->nvpfault_buffer, 0x1c, 0x80000000, 0x00000000); + + ret = compote_pfault_handler(cfile, &pfault); + if (ret) { + /* Kill threads */ + nvif_wr32(&device->object, 0x100cbc, 0x80000000 | (4 << 3) | + (compote_pfault_client(&pfault) << 9) | + (compote_pfault_gpc(&pfault) << 15) | + (compote_pfault_isgpc(&pfault) << 20)); + } else { + /* Resume threads */ + nvif_wr32(&device->object, 0x100cbc, 0x80000000 | (1 << 3) | + (compote_pfault_client(&pfault) << 9) | + (compote_pfault_gpc(&pfault) << 15) | + (compote_pfault_isgpc(&pfault) << 20)); + } + } + + return NVIF_NOTIFY_KEEP; +} + +int compote_file_pfault_init(struct compote_file *cfile) +{ + struct nvif_device *device = &cfile->nvclient.device; + int ret; + + /* Allocate replayable fault buffer. */ + ret = nvif_object_init(&device->object, 0, MAXWELL_FAULT_BUFFER_A, + NULL, 0, &cfile->nvpfault_buffer); + if (ret) + return ret; + nvif_object_map(&cfile->nvpfault_buffer); + + /* Request notification of pending replayable faults. */ + ret = nvif_notify_init(&cfile->nvpfault_buffer, + compote_file_pfault_process, + true, NVB069_VN_NTFY_FAULT, + NULL, 0, 0, + &cfile->nvpfault_notifier); + if (ret) + goto error; + ret = nvif_notify_get(&cfile->nvpfault_notifier); + if (ret) + goto error_get; + + return 0; + +error_get: + nvif_notify_fini(&cfile->nvpfault_notifier); +error: + nvif_object_fini(&cfile->nvpfault_buffer); + return ret; +} + +void compote_file_pfault_fini(struct compote_file *cfile) +{ + nvif_notify_put(&cfile->nvpfault_notifier); + nvif_notify_fini(&cfile->nvpfault_notifier); + nvif_object_fini(&cfile->nvpfault_buffer); +} diff --git a/drivers/gpu/drm/nouveau/compote/compote.h b/drivers/gpu/drm/nouveau/compote/compote.h index 23900689409a..b0fff7fa7cb9 100644 --- a/drivers/gpu/drm/nouveau/compote/compote.h +++ b/drivers/gpu/drm/nouveau/compote/compote.h @@ -38,6 +38,8 @@ struct compote_file { struct rw_semaphore rwsem; struct mm_struct *mm; struct hmm_mirror mirror; + struct nvif_notify nvpfault_notifier; + struct nvif_object nvpfault_buffer; }; struct compote_mo { @@ -84,4 +86,7 @@ int compote_mo_mmap(struct compote_file *cfile, int compote_file_hmm_init(struct compote_file *cfile); void compote_file_hmm_fini(struct compote_file *cfile); +int compote_file_pfault_init(struct compote_file *cfile); +void compote_file_pfault_fini(struct compote_file *cfile); + #endif /* COMPOTE_H */ -- cgit v1.2.3