From 1ce466894b532dc26b02a334fc609378b9231ea8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 May 2018 20:39:46 +1000 Subject: drm/nouveau/core: define FAULT subdev This will be responsible for the handling of MMU fault buffers on GPUs that support them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h (limited to 'drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h') diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h new file mode 100644 index 000000000000..35a9cfc9301d --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h @@ -0,0 +1,8 @@ +#ifndef __NVKM_FAULT_H__ +#define __NVKM_FAULT_H__ +#include + +struct nvkm_fault { + struct nvkm_subdev subdev; +}; +#endif -- cgit From 36780d7eee827047bd9e736f6e2c0be650f30b4e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 May 2018 20:39:46 +1000 Subject: drm/nouveau/fault: add infrastructure to support fault buffers GPU-specific support will be added separately. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/fault.h | 6 + drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c | 179 +++++++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h | 34 ++++ 4 files changed, 220 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h (limited to 'drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h') diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h index 35a9cfc9301d..6ba9c179aa09 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h @@ -3,6 +3,12 @@ #include struct nvkm_fault { + const struct nvkm_fault_func *func; struct nvkm_subdev subdev; + + struct nvkm_fault_buffer *buffer[1]; + int buffer_nr; + + struct nvkm_event event; }; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild index e69de29bb2d1..2e4c226634a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild @@ -0,0 +1 @@ +nvkm-y += nvkm/subdev/fault/base.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c new file mode 100644 index 000000000000..007bf4af33b9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c @@ -0,0 +1,179 @@ +/* + * 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 "priv.h" + +#include +#include +#include +#include + +static void +nvkm_fault_ntfy_fini(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fault *fault = container_of(event, typeof(*fault), event); + fault->func->buffer.fini(fault->buffer[index]); +} + +static void +nvkm_fault_ntfy_init(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fault *fault = container_of(event, typeof(*fault), event); + fault->func->buffer.init(fault->buffer[index]); +} + +static int +nvkm_fault_ntfy_ctor(struct nvkm_object *object, void *argv, u32 argc, + struct nvkm_notify *notify) +{ + struct nvkm_fault_buffer *buffer = nvkm_fault_buffer(object); + if (argc == 0) { + notify->size = 0; + notify->types = 1; + notify->index = buffer->id; + return 0; + } + return -ENOSYS; +} + +static const struct nvkm_event_func +nvkm_fault_ntfy = { + .ctor = nvkm_fault_ntfy_ctor, + .init = nvkm_fault_ntfy_init, + .fini = nvkm_fault_ntfy_fini, +}; + +static void +nvkm_fault_intr(struct nvkm_subdev *subdev) +{ + struct nvkm_fault *fault = nvkm_fault(subdev); + return fault->func->intr(fault); +} + +static int +nvkm_fault_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_fault *fault = nvkm_fault(subdev); + if (fault->func->fini) + fault->func->fini(fault); + return 0; +} + +static int +nvkm_fault_init(struct nvkm_subdev *subdev) +{ + struct nvkm_fault *fault = nvkm_fault(subdev); + if (fault->func->init) + fault->func->init(fault); + return 0; +} + +static int +nvkm_fault_oneinit_buffer(struct nvkm_fault *fault, int id) +{ + struct nvkm_subdev *subdev = &fault->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_vmm *bar2 = nvkm_bar_bar2_vmm(device); + struct nvkm_fault_buffer *buffer; + int ret; + + if (!(buffer = kzalloc(sizeof(*buffer), GFP_KERNEL))) + return -ENOMEM; + buffer->fault = fault; + buffer->id = id; + buffer->entries = fault->func->buffer.entries(buffer); + fault->buffer[id] = buffer; + + nvkm_debug(subdev, "buffer %d: %d entries\n", id, buffer->entries); + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, buffer->entries * + fault->func->buffer.entry_size, 0x1000, true, + &buffer->mem); + if (ret) + return ret; + + ret = nvkm_vmm_get(bar2, 12, nvkm_memory_size(buffer->mem), + &buffer->vma); + if (ret) + return ret; + + return nvkm_memory_map(buffer->mem, 0, bar2, buffer->vma, NULL, 0); +} + +static int +nvkm_fault_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_fault *fault = nvkm_fault(subdev); + int ret, i; + + for (i = 0; i < ARRAY_SIZE(fault->buffer); i++) { + if (i < fault->func->buffer.nr) { + ret = nvkm_fault_oneinit_buffer(fault, i); + if (ret) + return ret; + fault->buffer_nr = i + 1; + } + } + + return nvkm_event_init(&nvkm_fault_ntfy, 1, fault->buffer_nr, + &fault->event); +} + +static void * +nvkm_fault_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_vmm *bar2 = nvkm_bar_bar2_vmm(subdev->device); + struct nvkm_fault *fault = nvkm_fault(subdev); + int i; + + nvkm_event_fini(&fault->event); + + for (i = 0; i < fault->buffer_nr; i++) { + if (fault->buffer[i]) { + nvkm_vmm_put(bar2, &fault->buffer[i]->vma); + nvkm_memory_unref(&fault->buffer[i]->mem); + kfree(fault->buffer[i]); + } + } + + return fault; +} + +static const struct nvkm_subdev_func +nvkm_fault = { + .dtor = nvkm_fault_dtor, + .oneinit = nvkm_fault_oneinit, + .init = nvkm_fault_init, + .fini = nvkm_fault_fini, + .intr = nvkm_fault_intr, +}; + +int +nvkm_fault_new_(const struct nvkm_fault_func *func, struct nvkm_device *device, + int index, struct nvkm_fault **pfault) +{ + struct nvkm_fault *fault; + if (!(fault = *pfault = kzalloc(sizeof(*fault), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_fault, device, index, &fault->subdev); + fault->func = func; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h new file mode 100644 index 000000000000..44843ecf12b0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h @@ -0,0 +1,34 @@ +#ifndef __NVKM_FAULT_PRIV_H__ +#define __NVKM_FAULT_PRIV_H__ +#define nvkm_fault_buffer(p) container_of((p), struct nvkm_fault_buffer, object) +#define nvkm_fault(p) container_of((p), struct nvkm_fault, subdev) +#include + +#include +#include + +struct nvkm_fault_buffer { + struct nvkm_object object; + struct nvkm_fault *fault; + int id; + int entries; + struct nvkm_memory *mem; + struct nvkm_vma *vma; +}; + +int nvkm_fault_new_(const struct nvkm_fault_func *, struct nvkm_device *, + int index, struct nvkm_fault **); + +struct nvkm_fault_func { + void (*init)(struct nvkm_fault *); + void (*fini)(struct nvkm_fault *); + void (*intr)(struct nvkm_fault *); + struct { + int nr; + u32 entry_size; + u32 (*entries)(struct nvkm_fault_buffer *); + void (*init)(struct nvkm_fault_buffer *); + void (*fini)(struct nvkm_fault_buffer *); + } buffer; +}; +#endif -- cgit From d0e9351e420695907e28e921d3786265253787c1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 May 2018 20:39:46 +1000 Subject: drm/nouveau/fault/gp100: implement replayable fault buffer initialisation Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/fault.h | 2 + drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 7 +++ drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c | 69 ++++++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c (limited to 'drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h') diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h index 6ba9c179aa09..8ca66e572779 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h @@ -11,4 +11,6 @@ struct nvkm_fault { struct nvkm_event event; }; + +int gp100_fault_new(struct nvkm_device *, int, struct nvkm_fault **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 70f3cc0844c9..379e701962a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2161,6 +2161,7 @@ nv130_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gm200_devinit_new, + .fault = gp100_fault_new, .fb = gp100_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, @@ -2196,6 +2197,7 @@ nv132_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gm200_devinit_new, + .fault = gp100_fault_new, .fb = gp102_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, @@ -2231,6 +2233,7 @@ nv134_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gm200_devinit_new, + .fault = gp100_fault_new, .fb = gp102_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, @@ -2266,6 +2269,7 @@ nv136_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gm200_devinit_new, + .fault = gp100_fault_new, .fb = gp102_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, @@ -2301,6 +2305,7 @@ nv137_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gm200_devinit_new, + .fault = gp100_fault_new, .fb = gp102_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, @@ -2336,6 +2341,7 @@ nv138_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gm200_devinit_new, + .fault = gp100_fault_new, .fb = gp102_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, @@ -2369,6 +2375,7 @@ nv13b_chipset = { .name = "GP10B", .bar = gm20b_bar_new, .bus = gf100_bus_new, + .fault = gp100_fault_new, .fb = gp10b_fb_new, .fuse = gm107_fuse_new, .ibus = gp10b_ibus_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild index 2e4c226634a1..807ea402a162 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild @@ -1 +1,2 @@ nvkm-y += nvkm/subdev/fault/base.o +nvkm-y += nvkm/subdev/fault/gp100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c new file mode 100644 index 000000000000..5e71db2e8d75 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gp100.c @@ -0,0 +1,69 @@ +/* + * 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 "priv.h" + +#include + +static void +gp100_fault_buffer_fini(struct nvkm_fault_buffer *buffer) +{ + struct nvkm_device *device = buffer->fault->subdev.device; + nvkm_mask(device, 0x002a70, 0x00000001, 0x00000000); +} + +static void +gp100_fault_buffer_init(struct nvkm_fault_buffer *buffer) +{ + struct nvkm_device *device = buffer->fault->subdev.device; + nvkm_wr32(device, 0x002a74, upper_32_bits(buffer->vma->addr)); + nvkm_wr32(device, 0x002a70, lower_32_bits(buffer->vma->addr)); + nvkm_mask(device, 0x002a70, 0x00000001, 0x00000001); +} + +static u32 +gp100_fault_buffer_entries(struct nvkm_fault_buffer *buffer) +{ + return nvkm_rd32(buffer->fault->subdev.device, 0x002a78); +} + +static void +gp100_fault_intr(struct nvkm_fault *fault) +{ + nvkm_event_send(&fault->event, 1, 0, NULL, 0); +} + +static const struct nvkm_fault_func +gp100_fault = { + .intr = gp100_fault_intr, + .buffer.nr = 1, + .buffer.entry_size = 32, + .buffer.entries = gp100_fault_buffer_entries, + .buffer.init = gp100_fault_buffer_init, + .buffer.fini = gp100_fault_buffer_fini, +}; + +int +gp100_fault_new(struct nvkm_device *device, int index, + struct nvkm_fault **pfault) +{ + return nvkm_fault_new_(&gp100_fault, device, index, pfault); +} -- cgit From ddc669e25645b32158cc2b6da26faf5dac92fffc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 May 2018 20:39:46 +1000 Subject: drm/nouveau/fifo/gk104-: allow fault recovery code to be called by other subdevs This will be required to support Volta. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h | 2 + .../gpu/drm/nouveau/include/nvkm/subdev/fault.h | 13 ++ drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c | 6 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 191 ++++++++++++--------- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h | 21 +-- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h | 1 + 14 files changed, 141 insertions(+), 101 deletions(-) (limited to 'drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h') diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index c17b3a9bf8fb..0d96edee1e6a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -4,6 +4,7 @@ #include #include #include +struct nvkm_fault_data; #define NVKM_FIFO_CHID_NR 4096 @@ -45,6 +46,7 @@ struct nvkm_fifo { struct nvkm_event kevent; /* channel killed */ }; +void nvkm_fifo_fault(struct nvkm_fifo *, struct nvkm_fault_data *); void nvkm_fifo_pause(struct nvkm_fifo *, unsigned long *); void nvkm_fifo_start(struct nvkm_fifo *, unsigned long *); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h index 8ca66e572779..8e9bc30fe65d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h @@ -12,5 +12,18 @@ struct nvkm_fault { struct nvkm_event event; }; +struct nvkm_fault_data { + u64 addr; + u64 inst; + u64 time; + u8 engine; + u8 valid; + u8 gpc; + u8 hub; + u8 access; + u8 client; + u8 reason; +}; + int gp100_fault_new(struct nvkm_device *, int, struct nvkm_fault **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index 49b37a8a94b7..ed56087b4abe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -56,6 +56,12 @@ nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags) return fifo->func->start(fifo, flags); } +void +nvkm_fifo_fault(struct nvkm_fifo *fifo, struct nvkm_fault_data *info) +{ + return fifo->func->fault(fifo, info); +} + void nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags, struct nvkm_fifo_chan **pchan) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 84bd703dd897..b5706b15a64d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -347,6 +348,90 @@ gk104_fifo_recover_engn(struct gk104_fifo *fifo, int engn) schedule_work(&fifo->recover.work); } +static void +gk104_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info) +{ + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + const struct nvkm_enum *er, *ee, *ec, *ea; + struct nvkm_engine *engine = NULL; + struct nvkm_fifo_chan *chan; + unsigned long flags; + char ct[8] = "HUB/", en[16] = ""; + int engn; + + er = nvkm_enum_find(fifo->func->fault.reason, info->reason); + ee = nvkm_enum_find(fifo->func->fault.engine, info->engine); + if (info->hub) { + ec = nvkm_enum_find(fifo->func->fault.hubclient, info->client); + } else { + ec = nvkm_enum_find(fifo->func->fault.gpcclient, info->client); + snprintf(ct, sizeof(ct), "GPC%d/", info->gpc); + } + ea = nvkm_enum_find(fifo->func->fault.access, info->access); + + if (ee && ee->data2) { + switch (ee->data2) { + case NVKM_SUBDEV_BAR: + nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); + break; + case NVKM_SUBDEV_INSTMEM: + nvkm_mask(device, 0x001714, 0x00000000, 0x00000000); + break; + case NVKM_ENGINE_IFB: + nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); + break; + default: + engine = nvkm_device_engine(device, ee->data2); + break; + } + } + + if (ee == NULL) { + enum nvkm_devidx engidx = nvkm_top_fault(device, info->engine); + if (engidx < NVKM_SUBDEV_NR) { + const char *src = nvkm_subdev_name[engidx]; + char *dst = en; + do { + *dst++ = toupper(*src++); + } while(*src); + engine = nvkm_device_engine(device, engidx); + } + } else { + snprintf(en, sizeof(en), "%s", ee->name); + } + + spin_lock_irqsave(&fifo->base.lock, flags); + chan = nvkm_fifo_chan_inst_locked(&fifo->base, info->inst); + + nvkm_error(subdev, + "fault %02x [%s] at %016llx engine %02x [%s] client %02x " + "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n", + info->access, ea ? ea->name : "", info->addr, + info->engine, ee ? ee->name : en, + info->client, ct, ec ? ec->name : "", + info->reason, er ? er->name : "", chan ? chan->chid : -1, + info->inst, chan ? chan->object.client->name : "unknown"); + + /* Kill the channel that caused the fault. */ + if (chan) + gk104_fifo_recover_chan(&fifo->base, chan->chid); + + /* Channel recovery will probably have already done this for the + * correct engine(s), but just in case we can't find the channel + * information... + */ + for (engn = 0; engn < fifo->engine_nr && engine; engn++) { + if (fifo->engine[engn].engine == engine) { + gk104_fifo_recover_engn(fifo, engn); + break; + } + } + + spin_unlock_irqrestore(&fifo->base.lock, flags); +} + static const struct nvkm_enum gk104_fifo_bind_reason[] = { { 0x01, "BIND_NOT_UNBOUND" }, @@ -456,88 +541,21 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10)); u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10)); - u32 stat = nvkm_rd32(device, 0x00280c + (unit * 0x10)); - u32 gpc = (stat & 0x1f000000) >> 24; - u32 client = (stat & 0x00001f00) >> 8; - u32 write = (stat & 0x00000080); - u32 hub = (stat & 0x00000040); - u32 reason = (stat & 0x0000000f); - const struct nvkm_enum *er, *eu, *ec; - struct nvkm_engine *engine = NULL; - struct nvkm_fifo_chan *chan; - unsigned long flags; - char gpcid[8] = "", en[16] = ""; - int engn; - - er = nvkm_enum_find(fifo->func->fault.reason, reason); - eu = nvkm_enum_find(fifo->func->fault.engine, unit); - if (hub) { - ec = nvkm_enum_find(fifo->func->fault.hubclient, client); - } else { - ec = nvkm_enum_find(fifo->func->fault.gpcclient, client); - snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc); - } - - if (eu && eu->data2) { - switch (eu->data2) { - case NVKM_SUBDEV_BAR: - nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); - break; - case NVKM_SUBDEV_INSTMEM: - nvkm_mask(device, 0x001714, 0x00000000, 0x00000000); - break; - case NVKM_ENGINE_IFB: - nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); - break; - default: - engine = nvkm_device_engine(device, eu->data2); - break; - } - } - - if (eu == NULL) { - enum nvkm_devidx engidx = nvkm_top_fault(device, unit); - if (engidx < NVKM_SUBDEV_NR) { - const char *src = nvkm_subdev_name[engidx]; - char *dst = en; - do { - *dst++ = toupper(*src++); - } while(*src); - engine = nvkm_device_engine(device, engidx); - } - } else { - snprintf(en, sizeof(en), "%s", eu->name); - } - - spin_lock_irqsave(&fifo->base.lock, flags); - chan = nvkm_fifo_chan_inst_locked(&fifo->base, (u64)inst << 12); - - nvkm_error(subdev, - "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " - "reason %02x [%s] on channel %d [%010llx %s]\n", - write ? "write" : "read", (u64)vahi << 32 | valo, - unit, en, client, gpcid, ec ? ec->name : "", - reason, er ? er->name : "", chan ? chan->chid : -1, - (u64)inst << 12, - chan ? chan->object.client->name : "unknown"); - - - /* Kill the channel that caused the fault. */ - if (chan) - gk104_fifo_recover_chan(&fifo->base, chan->chid); - - /* Channel recovery will probably have already done this for the - * correct engine(s), but just in case we can't find the channel - * information... - */ - for (engn = 0; engn < fifo->engine_nr && engine; engn++) { - if (fifo->engine[engn].engine == engine) { - gk104_fifo_recover_engn(fifo, engn); - break; - } - } - - spin_unlock_irqrestore(&fifo->base.lock, flags); + u32 type = nvkm_rd32(device, 0x00280c + (unit * 0x10)); + struct nvkm_fault_data info; + + info.inst = (u64)inst << 12; + info.addr = ((u64)vahi << 32) | valo; + info.time = 0; + info.engine = unit; + info.valid = 1; + info.gpc = (type & 0x1f000000) >> 24; + info.client = (type & 0x00001f00) >> 8; + info.access = (type & 0x00000080) >> 7; + info.hub = (type & 0x00000040) >> 6; + info.reason = (type & 0x000000ff); + + nvkm_fifo_fault(&fifo->base, &info); } static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { @@ -897,6 +915,7 @@ gk104_fifo_ = { .init = gk104_fifo_init, .fini = gk104_fifo_fini, .intr = gk104_fifo_intr, + .fault = gk104_fifo_fault, .uevent_init = gk104_fifo_uevent_init, .uevent_fini = gk104_fifo_uevent_fini, .recover_chan = gk104_fifo_recover_chan, @@ -918,6 +937,13 @@ gk104_fifo_new_(const struct gk104_fifo_func *func, struct nvkm_device *device, return nvkm_fifo_ctor(&gk104_fifo_, device, index, nr, &fifo->base); } +const struct nvkm_enum +gk104_fifo_fault_access[] = { + { 0x0, "READ" }, + { 0x1, "WRITE" }, + {} +}; + const struct nvkm_enum gk104_fifo_fault_engine[] = { { 0x00, "GR", NULL, NVKM_ENGINE_GR }, @@ -1035,6 +1061,7 @@ gk104_fifo_fault_gpcclient[] = { static const struct gk104_fifo_func gk104_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gk104_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h index 1579785cf941..0e8b57275e9d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h @@ -44,6 +44,7 @@ struct gk104_fifo { struct gk104_fifo_func { struct { + const struct nvkm_enum *access; const struct nvkm_enum *engine; const struct nvkm_enum *reason; const struct nvkm_enum *hubclient; @@ -59,25 +60,7 @@ void gk104_fifo_runlist_insert(struct gk104_fifo *, struct gk104_fifo_chan *); void gk104_fifo_runlist_remove(struct gk104_fifo *, struct gk104_fifo_chan *); void gk104_fifo_runlist_commit(struct gk104_fifo *, int runl); -static inline u64 -gk104_fifo_engine_subdev(int engine) -{ - switch (engine) { - case 0: return (1ULL << NVKM_ENGINE_GR) | - (1ULL << NVKM_ENGINE_SW) | - (1ULL << NVKM_ENGINE_CE2); - case 1: return (1ULL << NVKM_ENGINE_MSPDEC); - case 2: return (1ULL << NVKM_ENGINE_MSPPP); - case 3: return (1ULL << NVKM_ENGINE_MSVLD); - case 4: return (1ULL << NVKM_ENGINE_CE0); - case 5: return (1ULL << NVKM_ENGINE_CE1); - case 6: return (1ULL << NVKM_ENGINE_MSENC); - default: - WARN_ON(1); - return 0; - } -} - +extern const struct nvkm_enum gk104_fifo_fault_access[]; extern const struct nvkm_enum gk104_fifo_fault_engine[]; extern const struct nvkm_enum gk104_fifo_fault_reason[]; extern const struct nvkm_enum gk104_fifo_fault_hubclient[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c index b2f8ab7bf847..ad792b6830e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c @@ -26,6 +26,7 @@ static const struct gk104_fifo_func gk110_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gk104_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c index 160617d376e4..5402d22462e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c @@ -26,6 +26,7 @@ static const struct gk104_fifo_func gk208_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gk104_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c index be9f5c16ed7d..0d7f9f59f80c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c @@ -24,6 +24,7 @@ static const struct gk104_fifo_func gk20a_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gk104_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c index 29c080683b32..58a46ee5ee44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c @@ -49,6 +49,7 @@ gm107_fifo_fault_engine[] = { static const struct gk104_fifo_func gm107_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gm107_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c index b069f785c5d8..f84d5398aebe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c @@ -26,6 +26,7 @@ static const struct gk104_fifo_func gm200_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gm107_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c index 2ed87c2e8299..66399b9572a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c @@ -24,6 +24,7 @@ static const struct gk104_fifo_func gm20b_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gm107_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c index 41f16cf5a918..2b8a6cff7a68 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c @@ -50,6 +50,7 @@ gp100_fifo_fault_engine[] = { static const struct gk104_fifo_func gp100_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gp100_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c index 4af96c3e69ff..71b8d93b4368 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp10b.c @@ -24,6 +24,7 @@ static const struct gk104_fifo_func gp10b_fifo = { + .fault.access = gk104_fifo_fault_access, .fault.engine = gp100_fifo_fault_engine, .fault.reason = gk104_fifo_fault_reason, .fault.hubclient = gk104_fifo_fault_hubclient, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h index ae76b1aaccd4..df74b54773b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h @@ -21,6 +21,7 @@ struct nvkm_fifo_func { void (*init)(struct nvkm_fifo *); void (*fini)(struct nvkm_fifo *); void (*intr)(struct nvkm_fifo *); + void (*fault)(struct nvkm_fifo *, struct nvkm_fault_data *); void (*pause)(struct nvkm_fifo *, unsigned long *); void (*start)(struct nvkm_fifo *, unsigned long *); void (*uevent_init)(struct nvkm_fifo *); -- cgit From 8b811951c604e417b4511e3d17a75bb8c84b8f08 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 May 2018 20:39:47 +1000 Subject: drm/nouveau/fault/gv100: initial support Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/fault.h | 6 +- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c | 206 +++++++++++++++++++++ 4 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c (limited to 'drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h') diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h index 8e9bc30fe65d..5a77498fe6a0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fault.h @@ -1,15 +1,18 @@ #ifndef __NVKM_FAULT_H__ #define __NVKM_FAULT_H__ #include +#include struct nvkm_fault { const struct nvkm_fault_func *func; struct nvkm_subdev subdev; - struct nvkm_fault_buffer *buffer[1]; + struct nvkm_fault_buffer *buffer[2]; int buffer_nr; struct nvkm_event event; + + struct nvkm_notify nrpfb; }; struct nvkm_fault_data { @@ -26,4 +29,5 @@ struct nvkm_fault_data { }; int gp100_fault_new(struct nvkm_device *, int, struct nvkm_fault **); +int gv100_fault_new(struct nvkm_device *, int, struct nvkm_fault **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 6aaa3d9cb88c..7f0385dbed06 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2401,6 +2401,7 @@ nv140_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gv100_devinit_new, + .fault = gv100_fault_new, .fb = gv100_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild index 807ea402a162..45bb46fb0929 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/Kbuild @@ -1,2 +1,3 @@ nvkm-y += nvkm/subdev/fault/base.o nvkm-y += nvkm/subdev/fault/gp100.o +nvkm-y += nvkm/subdev/fault/gv100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c new file mode 100644 index 000000000000..73c7728b5969 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c @@ -0,0 +1,206 @@ +/* + * 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 "priv.h" + +#include +#include +#include + +static void +gv100_fault_buffer_process(struct nvkm_fault_buffer *buffer) +{ + struct nvkm_device *device = buffer->fault->subdev.device; + struct nvkm_memory *mem = buffer->mem; + const u32 foff = buffer->id * 0x14; + u32 get = nvkm_rd32(device, 0x100e2c + foff); + u32 put = nvkm_rd32(device, 0x100e30 + foff); + if (put == get) + return; + + nvkm_kmap(mem); + while (get != put) { + const u32 base = get * buffer->fault->func->buffer.entry_size; + const u32 instlo = nvkm_ro32(mem, base + 0x00); + const u32 insthi = nvkm_ro32(mem, base + 0x04); + const u32 addrlo = nvkm_ro32(mem, base + 0x08); + const u32 addrhi = nvkm_ro32(mem, base + 0x0c); + const u32 timelo = nvkm_ro32(mem, base + 0x10); + const u32 timehi = nvkm_ro32(mem, base + 0x14); + const u32 info0 = nvkm_ro32(mem, base + 0x18); + const u32 info1 = nvkm_ro32(mem, base + 0x1c); + struct nvkm_fault_data info; + + if (++get == buffer->entries) + get = 0; + nvkm_wr32(device, 0x100e2c + foff, get); + + info.addr = ((u64)addrhi << 32) | addrlo; + info.inst = ((u64)insthi << 32) | instlo; + info.time = ((u64)timehi << 32) | timelo; + info.engine = (info0 & 0x000000ff); + info.valid = (info1 & 0x80000000) >> 31; + info.gpc = (info1 & 0x1f000000) >> 24; + info.hub = (info1 & 0x00100000) >> 20; + info.access = (info1 & 0x000f0000) >> 16; + info.client = (info1 & 0x00007f00) >> 8; + info.reason = (info1 & 0x0000001f); + + nvkm_fifo_fault(device->fifo, &info); + } + nvkm_done(mem); +} + +static void +gv100_fault_buffer_fini(struct nvkm_fault_buffer *buffer) +{ + struct nvkm_device *device = buffer->fault->subdev.device; + const u32 intr = buffer->id ? 0x08000000 : 0x20000000; + const u32 foff = buffer->id * 0x14; + + nvkm_mask(device, 0x100a34, intr, intr); + nvkm_mask(device, 0x100e34 + foff, 0x80000000, 0x00000000); +} + +static void +gv100_fault_buffer_init(struct nvkm_fault_buffer *buffer) +{ + struct nvkm_device *device = buffer->fault->subdev.device; + const u32 intr = buffer->id ? 0x08000000 : 0x20000000; + const u32 foff = buffer->id * 0x14; + + nvkm_mask(device, 0x100e34 + foff, 0xc0000000, 0x40000000); + nvkm_wr32(device, 0x100e28 + foff, upper_32_bits(buffer->vma->addr)); + nvkm_wr32(device, 0x100e24 + foff, lower_32_bits(buffer->vma->addr)); + nvkm_mask(device, 0x100e34 + foff, 0x80000000, 0x80000000); + nvkm_mask(device, 0x100a2c, intr, intr); +} + +static u32 +gv100_fault_buffer_entries(struct nvkm_fault_buffer *buffer) +{ + struct nvkm_device *device = buffer->fault->subdev.device; + const u32 foff = buffer->id * 0x14; + nvkm_mask(device, 0x100e34 + foff, 0x40000000, 0x40000000); + return nvkm_rd32(device, 0x100e34 + foff) & 0x000fffff; +} + +static int +gv100_fault_ntfy_nrpfb(struct nvkm_notify *notify) +{ + struct nvkm_fault *fault = container_of(notify, typeof(*fault), nrpfb); + gv100_fault_buffer_process(fault->buffer[0]); + return NVKM_NOTIFY_KEEP; +} + +static void +gv100_fault_intr_fault(struct nvkm_fault *fault) +{ + struct nvkm_subdev *subdev = &fault->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_fault_data info; + const u32 addrlo = nvkm_rd32(device, 0x100e4c); + const u32 addrhi = nvkm_rd32(device, 0x100e50); + const u32 info0 = nvkm_rd32(device, 0x100e54); + const u32 insthi = nvkm_rd32(device, 0x100e58); + const u32 info1 = nvkm_rd32(device, 0x100e5c); + + info.addr = ((u64)addrhi << 32) | addrlo; + info.inst = ((u64)insthi << 32) | (info0 & 0xfffff000); + info.time = 0; + info.engine = (info0 & 0x000000ff); + info.valid = (info1 & 0x80000000) >> 31; + info.gpc = (info1 & 0x1f000000) >> 24; + info.hub = (info1 & 0x00100000) >> 20; + info.access = (info1 & 0x000f0000) >> 16; + info.client = (info1 & 0x00007f00) >> 8; + info.reason = (info1 & 0x0000001f); + + nvkm_fifo_fault(device->fifo, &info); +} + +static void +gv100_fault_intr(struct nvkm_fault *fault) +{ + struct nvkm_subdev *subdev = &fault->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x100a20); + + if (stat & 0x80000000) { + gv100_fault_intr_fault(fault); + nvkm_wr32(device, 0x100e60, 0x80000000); + stat &= ~0x80000000; + } + + if (stat & 0x20000000) { + if (fault->buffer[0]) { + nvkm_event_send(&fault->event, 1, 0, NULL, 0); + stat &= ~0x20000000; + } + } + + if (stat) { + nvkm_debug(subdev, "intr %08x\n", stat); + } +} + +static void +gv100_fault_fini(struct nvkm_fault *fault) +{ + nvkm_notify_put(&fault->nrpfb); + nvkm_mask(fault->subdev.device, 0x100a34, 0x80000000, 0x80000000); +} + +static void +gv100_fault_init(struct nvkm_fault *fault) +{ + nvkm_mask(fault->subdev.device, 0x100a2c, 0x80000000, 0x80000000); + nvkm_notify_get(&fault->nrpfb); +} + +static const struct nvkm_fault_func +gv100_fault = { + .init = gv100_fault_init, + .fini = gv100_fault_fini, + .intr = gv100_fault_intr, + .buffer.nr = 2, + .buffer.entry_size = 32, + .buffer.entries = gv100_fault_buffer_entries, + .buffer.init = gv100_fault_buffer_init, + .buffer.fini = gv100_fault_buffer_fini, +}; + +int +gv100_fault_new(struct nvkm_device *device, int index, + struct nvkm_fault **pfault) +{ + struct nvkm_fault *fault; + int ret; + + ret = nvkm_fault_new_(&gv100_fault, device, index, &fault); + *pfault = fault; + if (ret) + return ret; + + return nvkm_notify_init(&fault->buffer[0]->object, &fault->event, + gv100_fault_ntfy_nrpfb, false, NULL, 0, 0, + &fault->nrpfb); +} -- cgit