xref: /openbmc/linux/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
18b811951SBen Skeggs /*
28b811951SBen Skeggs  * Copyright 2018 Red Hat Inc.
38b811951SBen Skeggs  *
48b811951SBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
58b811951SBen Skeggs  * copy of this software and associated documentation files (the "Software"),
68b811951SBen Skeggs  * to deal in the Software without restriction, including without limitation
78b811951SBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88b811951SBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
98b811951SBen Skeggs  * Software is furnished to do so, subject to the following conditions:
108b811951SBen Skeggs  *
118b811951SBen Skeggs  * The above copyright notice and this permission notice shall be included in
128b811951SBen Skeggs  * all copies or substantial portions of the Software.
138b811951SBen Skeggs  *
148b811951SBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158b811951SBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168b811951SBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178b811951SBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188b811951SBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198b811951SBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208b811951SBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
218b811951SBen Skeggs  */
228b811951SBen Skeggs #include "priv.h"
238b811951SBen Skeggs 
248b811951SBen Skeggs #include <core/memory.h>
258b811951SBen Skeggs #include <subdev/mmu.h>
268b811951SBen Skeggs #include <engine/fifo.h>
278b811951SBen Skeggs 
28a261a20cSBen Skeggs #include <nvif/class.h>
29a261a20cSBen Skeggs 
3055520832SBen Skeggs void
gv100_fault_buffer_process(struct work_struct * work)3155520832SBen Skeggs gv100_fault_buffer_process(struct work_struct *work)
328b811951SBen Skeggs {
3355520832SBen Skeggs 	struct nvkm_fault *fault = container_of(work, typeof(*fault), nrpfb_work);
3455520832SBen Skeggs 	struct nvkm_fault_buffer *buffer = fault->buffer[0];
3555520832SBen Skeggs 	struct nvkm_device *device = fault->subdev.device;
368b811951SBen Skeggs 	struct nvkm_memory *mem = buffer->mem;
3780972456SBen Skeggs 	u32 get = nvkm_rd32(device, buffer->get);
3880972456SBen Skeggs 	u32 put = nvkm_rd32(device, buffer->put);
398b811951SBen Skeggs 	if (put == get)
408b811951SBen Skeggs 		return;
418b811951SBen Skeggs 
428b811951SBen Skeggs 	nvkm_kmap(mem);
438b811951SBen Skeggs 	while (get != put) {
448b811951SBen Skeggs 		const u32   base = get * buffer->fault->func->buffer.entry_size;
458b811951SBen Skeggs 		const u32 instlo = nvkm_ro32(mem, base + 0x00);
468b811951SBen Skeggs 		const u32 insthi = nvkm_ro32(mem, base + 0x04);
478b811951SBen Skeggs 		const u32 addrlo = nvkm_ro32(mem, base + 0x08);
488b811951SBen Skeggs 		const u32 addrhi = nvkm_ro32(mem, base + 0x0c);
498b811951SBen Skeggs 		const u32 timelo = nvkm_ro32(mem, base + 0x10);
508b811951SBen Skeggs 		const u32 timehi = nvkm_ro32(mem, base + 0x14);
518b811951SBen Skeggs 		const u32  info0 = nvkm_ro32(mem, base + 0x18);
528b811951SBen Skeggs 		const u32  info1 = nvkm_ro32(mem, base + 0x1c);
538b811951SBen Skeggs 		struct nvkm_fault_data info;
548b811951SBen Skeggs 
558b811951SBen Skeggs 		if (++get == buffer->entries)
568b811951SBen Skeggs 			get = 0;
5780972456SBen Skeggs 		nvkm_wr32(device, buffer->get, get);
588b811951SBen Skeggs 
598b811951SBen Skeggs 		info.addr   = ((u64)addrhi << 32) | addrlo;
608b811951SBen Skeggs 		info.inst   = ((u64)insthi << 32) | instlo;
618b811951SBen Skeggs 		info.time   = ((u64)timehi << 32) | timelo;
628b811951SBen Skeggs 		info.engine = (info0 & 0x000000ff);
638b811951SBen Skeggs 		info.valid  = (info1 & 0x80000000) >> 31;
648b811951SBen Skeggs 		info.gpc    = (info1 & 0x1f000000) >> 24;
658b811951SBen Skeggs 		info.hub    = (info1 & 0x00100000) >> 20;
668b811951SBen Skeggs 		info.access = (info1 & 0x000f0000) >> 16;
678b811951SBen Skeggs 		info.client = (info1 & 0x00007f00) >> 8;
688b811951SBen Skeggs 		info.reason = (info1 & 0x0000001f);
698b811951SBen Skeggs 
708b811951SBen Skeggs 		nvkm_fifo_fault(device->fifo, &info);
718b811951SBen Skeggs 	}
728b811951SBen Skeggs 	nvkm_done(mem);
738b811951SBen Skeggs }
748b811951SBen Skeggs 
758b811951SBen Skeggs static void
gv100_fault_buffer_intr(struct nvkm_fault_buffer * buffer,bool enable)763968d692SBen Skeggs gv100_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
778b811951SBen Skeggs {
788b811951SBen Skeggs 	struct nvkm_device *device = buffer->fault->subdev.device;
798b811951SBen Skeggs 	const u32 intr = buffer->id ? 0x08000000 : 0x20000000;
803968d692SBen Skeggs 	if (enable)
813968d692SBen Skeggs 		nvkm_mask(device, 0x100a2c, intr, intr);
823968d692SBen Skeggs 	else
838b811951SBen Skeggs 		nvkm_mask(device, 0x100a34, intr, intr);
843968d692SBen Skeggs }
853968d692SBen Skeggs 
863968d692SBen Skeggs static void
gv100_fault_buffer_fini(struct nvkm_fault_buffer * buffer)873968d692SBen Skeggs gv100_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
883968d692SBen Skeggs {
893968d692SBen Skeggs 	struct nvkm_device *device = buffer->fault->subdev.device;
903968d692SBen Skeggs 	const u32 foff = buffer->id * 0x14;
918b811951SBen Skeggs 	nvkm_mask(device, 0x100e34 + foff, 0x80000000, 0x00000000);
928b811951SBen Skeggs }
938b811951SBen Skeggs 
948b811951SBen Skeggs static void
gv100_fault_buffer_init(struct nvkm_fault_buffer * buffer)958b811951SBen Skeggs gv100_fault_buffer_init(struct nvkm_fault_buffer *buffer)
968b811951SBen Skeggs {
978b811951SBen Skeggs 	struct nvkm_device *device = buffer->fault->subdev.device;
988b811951SBen Skeggs 	const u32 foff = buffer->id * 0x14;
998b811951SBen Skeggs 
1008b811951SBen Skeggs 	nvkm_mask(device, 0x100e34 + foff, 0xc0000000, 0x40000000);
1014d326469SBen Skeggs 	nvkm_wr32(device, 0x100e28 + foff, upper_32_bits(buffer->addr));
1024d326469SBen Skeggs 	nvkm_wr32(device, 0x100e24 + foff, lower_32_bits(buffer->addr));
1038b811951SBen Skeggs 	nvkm_mask(device, 0x100e34 + foff, 0x80000000, 0x80000000);
1048b811951SBen Skeggs }
1058b811951SBen Skeggs 
10680972456SBen Skeggs static void
gv100_fault_buffer_info(struct nvkm_fault_buffer * buffer)10780972456SBen Skeggs gv100_fault_buffer_info(struct nvkm_fault_buffer *buffer)
1088b811951SBen Skeggs {
1098b811951SBen Skeggs 	struct nvkm_device *device = buffer->fault->subdev.device;
1108b811951SBen Skeggs 	const u32 foff = buffer->id * 0x14;
11180972456SBen Skeggs 
1128b811951SBen Skeggs 	nvkm_mask(device, 0x100e34 + foff, 0x40000000, 0x40000000);
11380972456SBen Skeggs 
11480972456SBen Skeggs 	buffer->entries = nvkm_rd32(device, 0x100e34 + foff) & 0x000fffff;
11580972456SBen Skeggs 	buffer->get = 0x100e2c + foff;
11680972456SBen Skeggs 	buffer->put = 0x100e30 + foff;
1178b811951SBen Skeggs }
1188b811951SBen Skeggs 
1198b811951SBen Skeggs static int
gv100_fault_ntfy_nrpfb(struct nvkm_event_ntfy * ntfy,u32 bits)12055520832SBen Skeggs gv100_fault_ntfy_nrpfb(struct nvkm_event_ntfy *ntfy, u32 bits)
1218b811951SBen Skeggs {
12255520832SBen Skeggs 	struct nvkm_fault *fault = container_of(ntfy, typeof(*fault), nrpfb);
12355520832SBen Skeggs 
12455520832SBen Skeggs 	schedule_work(&fault->nrpfb_work);
12555520832SBen Skeggs 	return NVKM_EVENT_KEEP;
1268b811951SBen Skeggs }
1278b811951SBen Skeggs 
1288b811951SBen Skeggs static void
gv100_fault_intr_fault(struct nvkm_fault * fault)1298b811951SBen Skeggs gv100_fault_intr_fault(struct nvkm_fault *fault)
1308b811951SBen Skeggs {
1318b811951SBen Skeggs 	struct nvkm_subdev *subdev = &fault->subdev;
1328b811951SBen Skeggs 	struct nvkm_device *device = subdev->device;
1338b811951SBen Skeggs 	struct nvkm_fault_data info;
1348b811951SBen Skeggs 	const u32 addrlo = nvkm_rd32(device, 0x100e4c);
1358b811951SBen Skeggs 	const u32 addrhi = nvkm_rd32(device, 0x100e50);
1368b811951SBen Skeggs 	const u32  info0 = nvkm_rd32(device, 0x100e54);
1378b811951SBen Skeggs 	const u32 insthi = nvkm_rd32(device, 0x100e58);
1388b811951SBen Skeggs 	const u32  info1 = nvkm_rd32(device, 0x100e5c);
1398b811951SBen Skeggs 
1408b811951SBen Skeggs 	info.addr = ((u64)addrhi << 32) | addrlo;
1418b811951SBen Skeggs 	info.inst = ((u64)insthi << 32) | (info0 & 0xfffff000);
1428b811951SBen Skeggs 	info.time = 0;
1438b811951SBen Skeggs 	info.engine = (info0 & 0x000000ff);
1448b811951SBen Skeggs 	info.valid  = (info1 & 0x80000000) >> 31;
1458b811951SBen Skeggs 	info.gpc    = (info1 & 0x1f000000) >> 24;
1468b811951SBen Skeggs 	info.hub    = (info1 & 0x00100000) >> 20;
1478b811951SBen Skeggs 	info.access = (info1 & 0x000f0000) >> 16;
1488b811951SBen Skeggs 	info.client = (info1 & 0x00007f00) >> 8;
1498b811951SBen Skeggs 	info.reason = (info1 & 0x0000001f);
1508b811951SBen Skeggs 
1518b811951SBen Skeggs 	nvkm_fifo_fault(device->fifo, &info);
1528b811951SBen Skeggs }
1538b811951SBen Skeggs 
1548b811951SBen Skeggs static void
gv100_fault_intr(struct nvkm_fault * fault)1558b811951SBen Skeggs gv100_fault_intr(struct nvkm_fault *fault)
1568b811951SBen Skeggs {
1578b811951SBen Skeggs 	struct nvkm_subdev *subdev = &fault->subdev;
1588b811951SBen Skeggs 	struct nvkm_device *device = subdev->device;
1598b811951SBen Skeggs 	u32 stat = nvkm_rd32(device, 0x100a20);
1608b811951SBen Skeggs 
1618b811951SBen Skeggs 	if (stat & 0x80000000) {
1628b811951SBen Skeggs 		gv100_fault_intr_fault(fault);
1638b811951SBen Skeggs 		nvkm_wr32(device, 0x100e60, 0x80000000);
1648b811951SBen Skeggs 		stat &= ~0x80000000;
1658b811951SBen Skeggs 	}
1668b811951SBen Skeggs 
1678b811951SBen Skeggs 	if (stat & 0x20000000) {
1688b811951SBen Skeggs 		if (fault->buffer[0]) {
169*99d0701aSBen Skeggs 			nvkm_event_ntfy(&fault->event, 0, NVKM_FAULT_BUFFER_EVENT_PENDING);
1708b811951SBen Skeggs 			stat &= ~0x20000000;
1718b811951SBen Skeggs 		}
1728b811951SBen Skeggs 	}
1738b811951SBen Skeggs 
174a261a20cSBen Skeggs 	if (stat & 0x08000000) {
175a261a20cSBen Skeggs 		if (fault->buffer[1]) {
176*99d0701aSBen Skeggs 			nvkm_event_ntfy(&fault->event, 1, NVKM_FAULT_BUFFER_EVENT_PENDING);
177a261a20cSBen Skeggs 			stat &= ~0x08000000;
178a261a20cSBen Skeggs 		}
179a261a20cSBen Skeggs 	}
180a261a20cSBen Skeggs 
1818b811951SBen Skeggs 	if (stat) {
1828b811951SBen Skeggs 		nvkm_debug(subdev, "intr %08x\n", stat);
1838b811951SBen Skeggs 	}
1848b811951SBen Skeggs }
1858b811951SBen Skeggs 
1868b811951SBen Skeggs static void
gv100_fault_fini(struct nvkm_fault * fault)1878b811951SBen Skeggs gv100_fault_fini(struct nvkm_fault *fault)
1888b811951SBen Skeggs {
18955520832SBen Skeggs 	nvkm_event_ntfy_block(&fault->nrpfb);
19055520832SBen Skeggs 	flush_work(&fault->nrpfb_work);
19155520832SBen Skeggs 
1923968d692SBen Skeggs 	if (fault->buffer[0])
1933968d692SBen Skeggs 		fault->func->buffer.fini(fault->buffer[0]);
19455520832SBen Skeggs 
1958b811951SBen Skeggs 	nvkm_mask(fault->subdev.device, 0x100a34, 0x80000000, 0x80000000);
1968b811951SBen Skeggs }
1978b811951SBen Skeggs 
1988b811951SBen Skeggs static void
gv100_fault_init(struct nvkm_fault * fault)1998b811951SBen Skeggs gv100_fault_init(struct nvkm_fault *fault)
2008b811951SBen Skeggs {
2018b811951SBen Skeggs 	nvkm_mask(fault->subdev.device, 0x100a2c, 0x80000000, 0x80000000);
2023968d692SBen Skeggs 	fault->func->buffer.init(fault->buffer[0]);
20355520832SBen Skeggs 	nvkm_event_ntfy_allow(&fault->nrpfb);
2048b811951SBen Skeggs }
2058b811951SBen Skeggs 
20617fb2807SBen Skeggs int
gv100_fault_oneinit(struct nvkm_fault * fault)20760cda665SBen Skeggs gv100_fault_oneinit(struct nvkm_fault *fault)
20860cda665SBen Skeggs {
20955520832SBen Skeggs 	nvkm_event_ntfy_add(&fault->event, 0, NVKM_FAULT_BUFFER_EVENT_PENDING, true,
21055520832SBen Skeggs 			    gv100_fault_ntfy_nrpfb, &fault->nrpfb);
21155520832SBen Skeggs 	return 0;
21260cda665SBen Skeggs }
21360cda665SBen Skeggs 
2148b811951SBen Skeggs static const struct nvkm_fault_func
2158b811951SBen Skeggs gv100_fault = {
21660cda665SBen Skeggs 	.oneinit = gv100_fault_oneinit,
2178b811951SBen Skeggs 	.init = gv100_fault_init,
2188b811951SBen Skeggs 	.fini = gv100_fault_fini,
2198b811951SBen Skeggs 	.intr = gv100_fault_intr,
2208b811951SBen Skeggs 	.buffer.nr = 2,
2218b811951SBen Skeggs 	.buffer.entry_size = 32,
22280972456SBen Skeggs 	.buffer.info = gv100_fault_buffer_info,
2230ac7facbSThierry Reding 	.buffer.pin = gp100_fault_buffer_pin,
2248b811951SBen Skeggs 	.buffer.init = gv100_fault_buffer_init,
2258b811951SBen Skeggs 	.buffer.fini = gv100_fault_buffer_fini,
2263968d692SBen Skeggs 	.buffer.intr = gv100_fault_buffer_intr,
227a261a20cSBen Skeggs 	/*TODO: Figure out how to expose non-replayable fault buffer, which,
228a261a20cSBen Skeggs 	 *      for some reason, is where recoverable CE faults appear...
229a261a20cSBen Skeggs 	 *
230a261a20cSBen Skeggs 	 * 	It's a bit tricky, as both NVKM and SVM will need access to
231a261a20cSBen Skeggs 	 * 	the non-replayable fault buffer.
232a261a20cSBen Skeggs 	 */
233a261a20cSBen Skeggs 	.user = { { 0, 0, VOLTA_FAULT_BUFFER_A }, 1 },
2348b811951SBen Skeggs };
2358b811951SBen Skeggs 
2368b811951SBen Skeggs int
gv100_fault_new(struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_fault ** pfault)23777689f1bSBen Skeggs gv100_fault_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
2388b811951SBen Skeggs 		struct nvkm_fault **pfault)
2398b811951SBen Skeggs {
24055520832SBen Skeggs 	int ret = nvkm_fault_new_(&gv100_fault, device, type, inst, pfault);
24155520832SBen Skeggs 	if (ret)
24255520832SBen Skeggs 		return ret;
24355520832SBen Skeggs 
24455520832SBen Skeggs 	INIT_WORK(&(*pfault)->nrpfb_work, gv100_fault_buffer_process);
24555520832SBen Skeggs 	return 0;
2468b811951SBen Skeggs }
247