summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c120
1 files changed, 58 insertions, 62 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
index 91eb6729c84d..967efaddae28 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/tu102.c
@@ -24,20 +24,27 @@
#include <core/memory.h>
#include <subdev/mc.h>
#include <subdev/mmu.h>
+#include <subdev/vfn.h>
#include <engine/fifo.h>
#include <nvif/class.h>
+static irqreturn_t
+tu102_fault_buffer_notify(struct nvkm_inth *inth)
+{
+ struct nvkm_fault_buffer *buffer = container_of(inth, typeof(*buffer), inth);
+
+ nvkm_event_ntfy(&buffer->fault->event, buffer->id, NVKM_FAULT_BUFFER_EVENT_PENDING);
+ return IRQ_HANDLED;
+}
+
static void
tu102_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
{
- /*XXX: Earlier versions of RM touched the old regs on Turing,
- * which don't appear to actually work anymore, but newer
- * versions of RM don't appear to touch anything at all..
- */
- struct nvkm_device *device = buffer->fault->subdev.device;
-
- nvkm_mc_intr_mask(device, NVKM_SUBDEV_FAULT, 0, enable);
+ if (enable)
+ nvkm_inth_allow(&buffer->inth);
+ else
+ nvkm_inth_block(&buffer->inth);
}
static void
@@ -46,10 +53,6 @@ tu102_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
struct nvkm_device *device = buffer->fault->subdev.device;
const u32 foff = buffer->id * 0x20;
- /* Disable the fault interrupts */
- nvkm_wr32(device, 0xb81408, 0x1);
- nvkm_wr32(device, 0xb81410, 0x10);
-
nvkm_mask(device, 0xb83010 + foff, 0x80000000, 0x00000000);
}
@@ -59,10 +62,6 @@ tu102_fault_buffer_init(struct nvkm_fault_buffer *buffer)
struct nvkm_device *device = buffer->fault->subdev.device;
const u32 foff = buffer->id * 0x20;
- /* Enable the fault interrupts */
- nvkm_wr32(device, 0xb81208, 0x1);
- nvkm_wr32(device, 0xb81210, 0x10);
-
nvkm_mask(device, 0xb83010 + foff, 0xc0000000, 0x40000000);
nvkm_wr32(device, 0xb83004 + foff, upper_32_bits(buffer->addr));
nvkm_wr32(device, 0xb83000 + foff, lower_32_bits(buffer->addr));
@@ -82,9 +81,10 @@ tu102_fault_buffer_info(struct nvkm_fault_buffer *buffer)
buffer->put = 0xb8300c + foff;
}
-static void
-tu102_fault_intr_fault(struct nvkm_fault *fault)
+static irqreturn_t
+tu102_fault_info_fault(struct nvkm_inth *inth)
{
+ struct nvkm_fault *fault = container_of(inth, typeof(*fault), info_fault);
struct nvkm_subdev *subdev = &fault->subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_fault_data info;
@@ -106,70 +106,61 @@ tu102_fault_intr_fault(struct nvkm_fault *fault)
info.reason = (info1 & 0x0000001f);
nvkm_fifo_fault(device->fifo, &info);
-}
-
-static void
-tu102_fault_intr(struct nvkm_fault *fault)
-{
- struct nvkm_subdev *subdev = &fault->subdev;
- struct nvkm_device *device = subdev->device;
- u32 stat = nvkm_rd32(device, 0xb83094);
-
- if (stat & 0x80000000) {
- tu102_fault_intr_fault(fault);
- nvkm_wr32(device, 0xb83094, 0x80000000);
- stat &= ~0x80000000;
- }
- if (stat & 0x00000200) {
- /* Clear the associated interrupt flag */
- nvkm_wr32(device, 0xb81010, 0x10);
-
- if (fault->buffer[0]) {
- nvkm_event_send(&fault->event, 1, 0, NULL, 0);
- stat &= ~0x00000200;
- }
- }
-
- /* Replayable MMU fault */
- if (stat & 0x00000100) {
- /* Clear the associated interrupt flag */
- nvkm_wr32(device, 0xb81008, 0x1);
-
- if (fault->buffer[1]) {
- nvkm_event_send(&fault->event, 1, 1, NULL, 0);
- stat &= ~0x00000100;
- }
- }
-
- if (stat) {
- nvkm_debug(subdev, "intr %08x\n", stat);
- }
+ nvkm_wr32(device, 0xb83094, 0x80000000);
+ return IRQ_HANDLED;
}
static void
tu102_fault_fini(struct nvkm_fault *fault)
{
- nvkm_notify_put(&fault->nrpfb);
+ nvkm_event_ntfy_block(&fault->nrpfb);
+ flush_work(&fault->nrpfb_work);
+
if (fault->buffer[0])
fault->func->buffer.fini(fault->buffer[0]);
- /*XXX: disable priv faults */
+
+ nvkm_inth_block(&fault->info_fault);
}
static void
tu102_fault_init(struct nvkm_fault *fault)
{
- /*XXX: enable priv faults */
+ nvkm_inth_allow(&fault->info_fault);
+
fault->func->buffer.init(fault->buffer[0]);
- nvkm_notify_get(&fault->nrpfb);
+ nvkm_event_ntfy_allow(&fault->nrpfb);
+}
+
+static int
+tu102_fault_oneinit(struct nvkm_fault *fault)
+{
+ struct nvkm_device *device = fault->subdev.device;
+ struct nvkm_intr *intr = &device->vfn->intr;
+ int ret, i;
+
+ ret = nvkm_inth_add(intr, nvkm_rd32(device, 0x100ee0) & 0x0000ffff,
+ NVKM_INTR_PRIO_NORMAL, &fault->subdev, tu102_fault_info_fault,
+ &fault->info_fault);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < fault->buffer_nr; i++) {
+ ret = nvkm_inth_add(intr, nvkm_rd32(device, 0x100ee4 + (i * 4)) >> 16,
+ NVKM_INTR_PRIO_NORMAL, &fault->subdev,
+ tu102_fault_buffer_notify, &fault->buffer[i]->inth);
+ if (ret)
+ return ret;
+ }
+
+ return gv100_fault_oneinit(fault);
}
static const struct nvkm_fault_func
tu102_fault = {
- .oneinit = gv100_fault_oneinit,
+ .oneinit = tu102_fault_oneinit,
.init = tu102_fault_init,
.fini = tu102_fault_fini,
- .intr = tu102_fault_intr,
.buffer.nr = 2,
.buffer.entry_size = 32,
.buffer.info = tu102_fault_buffer_info,
@@ -184,5 +175,10 @@ int
tu102_fault_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_fault **pfault)
{
- return nvkm_fault_new_(&tu102_fault, device, type, inst, pfault);
+ int ret = nvkm_fault_new_(&tu102_fault, device, type, inst, pfault);
+ if (ret)
+ return ret;
+
+ INIT_WORK(&(*pfault)->nrpfb_work, gv100_fault_buffer_process);
+ return 0;
}