diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2018-05-08 06:39:47 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2018-05-18 01:01:38 -0400 |
commit | 8b811951c604e417b4511e3d17a75bb8c84b8f08 (patch) | |
tree | 60988ef26e5fb89bcae1d501168db54adeada4c3 | |
parent | 013b7b37739ca883b2dd5ef979e0e250ac3dafc1 (diff) |
drm/nouveau/fault/gv100: initial support
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
4 files changed, 213 insertions, 1 deletions
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 @@ | |||
1 | #ifndef __NVKM_FAULT_H__ | 1 | #ifndef __NVKM_FAULT_H__ |
2 | #define __NVKM_FAULT_H__ | 2 | #define __NVKM_FAULT_H__ |
3 | #include <core/subdev.h> | 3 | #include <core/subdev.h> |
4 | #include <core/notify.h> | ||
4 | 5 | ||
5 | struct nvkm_fault { | 6 | struct nvkm_fault { |
6 | const struct nvkm_fault_func *func; | 7 | const struct nvkm_fault_func *func; |
7 | struct nvkm_subdev subdev; | 8 | struct nvkm_subdev subdev; |
8 | 9 | ||
9 | struct nvkm_fault_buffer *buffer[1]; | 10 | struct nvkm_fault_buffer *buffer[2]; |
10 | int buffer_nr; | 11 | int buffer_nr; |
11 | 12 | ||
12 | struct nvkm_event event; | 13 | struct nvkm_event event; |
14 | |||
15 | struct nvkm_notify nrpfb; | ||
13 | }; | 16 | }; |
14 | 17 | ||
15 | struct nvkm_fault_data { | 18 | struct nvkm_fault_data { |
@@ -26,4 +29,5 @@ struct nvkm_fault_data { | |||
26 | }; | 29 | }; |
27 | 30 | ||
28 | int gp100_fault_new(struct nvkm_device *, int, struct nvkm_fault **); | 31 | int gp100_fault_new(struct nvkm_device *, int, struct nvkm_fault **); |
32 | int gv100_fault_new(struct nvkm_device *, int, struct nvkm_fault **); | ||
29 | #endif | 33 | #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 = { | |||
2401 | .bios = nvkm_bios_new, | 2401 | .bios = nvkm_bios_new, |
2402 | .bus = gf100_bus_new, | 2402 | .bus = gf100_bus_new, |
2403 | .devinit = gv100_devinit_new, | 2403 | .devinit = gv100_devinit_new, |
2404 | .fault = gv100_fault_new, | ||
2404 | .fb = gv100_fb_new, | 2405 | .fb = gv100_fb_new, |
2405 | .fuse = gm107_fuse_new, | 2406 | .fuse = gm107_fuse_new, |
2406 | .gpio = gk104_gpio_new, | 2407 | .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 @@ | |||
1 | nvkm-y += nvkm/subdev/fault/base.o | 1 | nvkm-y += nvkm/subdev/fault/base.o |
2 | nvkm-y += nvkm/subdev/fault/gp100.o | 2 | nvkm-y += nvkm/subdev/fault/gp100.o |
3 | 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 @@ | |||
1 | /* | ||
2 | * Copyright 2018 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | #include "priv.h" | ||
23 | |||
24 | #include <core/memory.h> | ||
25 | #include <subdev/mmu.h> | ||
26 | #include <engine/fifo.h> | ||
27 | |||
28 | static void | ||
29 | gv100_fault_buffer_process(struct nvkm_fault_buffer *buffer) | ||
30 | { | ||
31 | struct nvkm_device *device = buffer->fault->subdev.device; | ||
32 | struct nvkm_memory *mem = buffer->mem; | ||
33 | const u32 foff = buffer->id * 0x14; | ||
34 | u32 get = nvkm_rd32(device, 0x100e2c + foff); | ||
35 | u32 put = nvkm_rd32(device, 0x100e30 + foff); | ||
36 | if (put == get) | ||
37 | return; | ||
38 | |||
39 | nvkm_kmap(mem); | ||
40 | while (get != put) { | ||
41 | const u32 base = get * buffer->fault->func->buffer.entry_size; | ||
42 | const u32 instlo = nvkm_ro32(mem, base + 0x00); | ||
43 | const u32 insthi = nvkm_ro32(mem, base + 0x04); | ||
44 | const u32 addrlo = nvkm_ro32(mem, base + 0x08); | ||
45 | const u32 addrhi = nvkm_ro32(mem, base + 0x0c); | ||
46 | const u32 timelo = nvkm_ro32(mem, base + 0x10); | ||
47 | const u32 timehi = nvkm_ro32(mem, base + 0x14); | ||
48 | const u32 info0 = nvkm_ro32(mem, base + 0x18); | ||
49 | const u32 info1 = nvkm_ro32(mem, base + 0x1c); | ||
50 | struct nvkm_fault_data info; | ||
51 | |||
52 | if (++get == buffer->entries) | ||
53 | get = 0; | ||
54 | nvkm_wr32(device, 0x100e2c + foff, get); | ||
55 | |||
56 | info.addr = ((u64)addrhi << 32) | addrlo; | ||
57 | info.inst = ((u64)insthi << 32) | instlo; | ||
58 | info.time = ((u64)timehi << 32) | timelo; | ||
59 | info.engine = (info0 & 0x000000ff); | ||
60 | info.valid = (info1 & 0x80000000) >> 31; | ||
61 | info.gpc = (info1 & 0x1f000000) >> 24; | ||
62 | info.hub = (info1 & 0x00100000) >> 20; | ||
63 | info.access = (info1 & 0x000f0000) >> 16; | ||
64 | info.client = (info1 & 0x00007f00) >> 8; | ||
65 | info.reason = (info1 & 0x0000001f); | ||
66 | |||
67 | nvkm_fifo_fault(device->fifo, &info); | ||
68 | } | ||
69 | nvkm_done(mem); | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | gv100_fault_buffer_fini(struct nvkm_fault_buffer *buffer) | ||
74 | { | ||
75 | struct nvkm_device *device = buffer->fault->subdev.device; | ||
76 | const u32 intr = buffer->id ? 0x08000000 : 0x20000000; | ||
77 | const u32 foff = buffer->id * 0x14; | ||
78 | |||
79 | nvkm_mask(device, 0x100a34, intr, intr); | ||
80 | nvkm_mask(device, 0x100e34 + foff, 0x80000000, 0x00000000); | ||
81 | } | ||
82 | |||
83 | static void | ||
84 | gv100_fault_buffer_init(struct nvkm_fault_buffer *buffer) | ||
85 | { | ||
86 | struct nvkm_device *device = buffer->fault->subdev.device; | ||
87 | const u32 intr = buffer->id ? 0x08000000 : 0x20000000; | ||
88 | const u32 foff = buffer->id * 0x14; | ||
89 | |||
90 | nvkm_mask(device, 0x100e34 + foff, 0xc0000000, 0x40000000); | ||
91 | nvkm_wr32(device, 0x100e28 + foff, upper_32_bits(buffer->vma->addr)); | ||
92 | nvkm_wr32(device, 0x100e24 + foff, lower_32_bits(buffer->vma->addr)); | ||
93 | nvkm_mask(device, 0x100e34 + foff, 0x80000000, 0x80000000); | ||
94 | nvkm_mask(device, 0x100a2c, intr, intr); | ||
95 | } | ||
96 | |||
97 | static u32 | ||
98 | gv100_fault_buffer_entries(struct nvkm_fault_buffer *buffer) | ||
99 | { | ||
100 | struct nvkm_device *device = buffer->fault->subdev.device; | ||
101 | const u32 foff = buffer->id * 0x14; | ||
102 | nvkm_mask(device, 0x100e34 + foff, 0x40000000, 0x40000000); | ||
103 | return nvkm_rd32(device, 0x100e34 + foff) & 0x000fffff; | ||
104 | } | ||
105 | |||
106 | static int | ||
107 | gv100_fault_ntfy_nrpfb(struct nvkm_notify *notify) | ||
108 | { | ||
109 | struct nvkm_fault *fault = container_of(notify, typeof(*fault), nrpfb); | ||
110 | gv100_fault_buffer_process(fault->buffer[0]); | ||
111 | return NVKM_NOTIFY_KEEP; | ||
112 | } | ||
113 | |||
114 | static void | ||
115 | gv100_fault_intr_fault(struct nvkm_fault *fault) | ||
116 | { | ||
117 | struct nvkm_subdev *subdev = &fault->subdev; | ||
118 | struct nvkm_device *device = subdev->device; | ||
119 | struct nvkm_fault_data info; | ||
120 | const u32 addrlo = nvkm_rd32(device, 0x100e4c); | ||
121 | const u32 addrhi = nvkm_rd32(device, 0x100e50); | ||
122 | const u32 info0 = nvkm_rd32(device, 0x100e54); | ||
123 | const u32 insthi = nvkm_rd32(device, 0x100e58); | ||
124 | const u32 info1 = nvkm_rd32(device, 0x100e5c); | ||
125 | |||
126 | info.addr = ((u64)addrhi << 32) | addrlo; | ||
127 | info.inst = ((u64)insthi << 32) | (info0 & 0xfffff000); | ||
128 | info.time = 0; | ||
129 | info.engine = (info0 & 0x000000ff); | ||
130 | info.valid = (info1 & 0x80000000) >> 31; | ||
131 | info.gpc = (info1 & 0x1f000000) >> 24; | ||
132 | info.hub = (info1 & 0x00100000) >> 20; | ||
133 | info.access = (info1 & 0x000f0000) >> 16; | ||
134 | info.client = (info1 & 0x00007f00) >> 8; | ||
135 | info.reason = (info1 & 0x0000001f); | ||
136 | |||
137 | nvkm_fifo_fault(device->fifo, &info); | ||
138 | } | ||
139 | |||
140 | static void | ||
141 | gv100_fault_intr(struct nvkm_fault *fault) | ||
142 | { | ||
143 | struct nvkm_subdev *subdev = &fault->subdev; | ||
144 | struct nvkm_device *device = subdev->device; | ||
145 | u32 stat = nvkm_rd32(device, 0x100a20); | ||
146 | |||
147 | if (stat & 0x80000000) { | ||
148 | gv100_fault_intr_fault(fault); | ||
149 | nvkm_wr32(device, 0x100e60, 0x80000000); | ||
150 | stat &= ~0x80000000; | ||
151 | } | ||
152 | |||
153 | if (stat & 0x20000000) { | ||
154 | if (fault->buffer[0]) { | ||
155 | nvkm_event_send(&fault->event, 1, 0, NULL, 0); | ||
156 | stat &= ~0x20000000; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | if (stat) { | ||
161 | nvkm_debug(subdev, "intr %08x\n", stat); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static void | ||
166 | gv100_fault_fini(struct nvkm_fault *fault) | ||
167 | { | ||
168 | nvkm_notify_put(&fault->nrpfb); | ||
169 | nvkm_mask(fault->subdev.device, 0x100a34, 0x80000000, 0x80000000); | ||
170 | } | ||
171 | |||
172 | static void | ||
173 | gv100_fault_init(struct nvkm_fault *fault) | ||
174 | { | ||
175 | nvkm_mask(fault->subdev.device, 0x100a2c, 0x80000000, 0x80000000); | ||
176 | nvkm_notify_get(&fault->nrpfb); | ||
177 | } | ||
178 | |||
179 | static const struct nvkm_fault_func | ||
180 | gv100_fault = { | ||
181 | .init = gv100_fault_init, | ||
182 | .fini = gv100_fault_fini, | ||
183 | .intr = gv100_fault_intr, | ||
184 | .buffer.nr = 2, | ||
185 | .buffer.entry_size = 32, | ||
186 | .buffer.entries = gv100_fault_buffer_entries, | ||
187 | .buffer.init = gv100_fault_buffer_init, | ||
188 | .buffer.fini = gv100_fault_buffer_fini, | ||
189 | }; | ||
190 | |||
191 | int | ||
192 | gv100_fault_new(struct nvkm_device *device, int index, | ||
193 | struct nvkm_fault **pfault) | ||
194 | { | ||
195 | struct nvkm_fault *fault; | ||
196 | int ret; | ||
197 | |||
198 | ret = nvkm_fault_new_(&gv100_fault, device, index, &fault); | ||
199 | *pfault = fault; | ||
200 | if (ret) | ||
201 | return ret; | ||
202 | |||
203 | return nvkm_notify_init(&fault->buffer[0]->object, &fault->event, | ||
204 | gv100_fault_ntfy_nrpfb, false, NULL, 0, 0, | ||
205 | &fault->nrpfb); | ||
206 | } | ||