Commit e4f90a35 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/tmr: detect stalled gpu timer and break out of waits



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent a31e24a7
Loading
Loading
Loading
Loading
+18 −10
Original line number Diff line number Diff line
@@ -28,6 +28,18 @@ struct nvkm_timer {
u64 nvkm_timer_read(struct nvkm_timer *);
void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *);

struct nvkm_timer_wait {
	struct nvkm_timer *tmr;
	u64 limit;
	u64 time0;
	u64 time1;
	int reads;
};

void nvkm_timer_wait_init(struct nvkm_device *, u64 nsec,
			  struct nvkm_timer_wait *);
s64 nvkm_timer_wait_test(struct nvkm_timer_wait *);

/* Delay based on GPU time (ie. PTIMER).
 *
 * Will return -ETIMEDOUT unless the loop was terminated with 'break',
@@ -38,21 +50,17 @@ void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *);
 */
#define NVKM_DELAY _warn = false;
#define nvkm_nsec(d,n,cond...) ({                                              \
	struct nvkm_device *_device = (d);                                     \
	struct nvkm_timer *_tmr = _device->timer;                              \
	u64 _nsecs = (n), _time0 = nvkm_timer_read(_tmr);                      \
	s64 _taken = 0;                                                        \
	struct nvkm_timer_wait _wait;                                          \
	bool _warn = true;                                                     \
	s64 _taken = 0;                                                        \
                                                                               \
	nvkm_timer_wait_init((d), (n), &_wait);                                \
	do {                                                                   \
		cond                                                           \
	} while (_taken = nvkm_timer_read(_tmr) - _time0, _taken < _nsecs);    \
	} while ((_taken = nvkm_timer_wait_test(&_wait)) >= 0);                \
                                                                               \
	if (_taken >= _nsecs) {                                                \
		if (_warn)                                                     \
			dev_WARN(_device->dev, "timeout\n");                   \
		_taken = -ETIMEDOUT;                                           \
	}                                                                      \
	if (_warn && _taken < 0)                                               \
		dev_WARN(_wait.tmr->subdev.device->dev, "timeout\n");          \
	_taken;                                                                \
})
#define nvkm_usec(d,u,cond...) nvkm_nsec((d), (u) * 1000, ##cond)
+36 −0
Original line number Diff line number Diff line
@@ -23,6 +23,42 @@
 */
#include "priv.h"

s64
nvkm_timer_wait_test(struct nvkm_timer_wait *wait)
{
	struct nvkm_subdev *subdev = &wait->tmr->subdev;
	u64 time = nvkm_timer_read(wait->tmr);

	if (wait->reads == 0) {
		wait->time0 = time;
		wait->time1 = time;
	}

	if (wait->time1 == time) {
		if (wait->reads++ == 16) {
			nvkm_fatal(subdev, "stalled at %016llx\n", time);
			return -ETIMEDOUT;
		}
	} else {
		wait->time1 = time;
		wait->reads = 1;
	}

	if (wait->time1 - wait->time0 > wait->limit)
		return -ETIMEDOUT;

	return wait->time1 - wait->time0;
}

void
nvkm_timer_wait_init(struct nvkm_device *device, u64 nsec,
		     struct nvkm_timer_wait *wait)
{
	wait->tmr = device->timer;
	wait->limit = nsec;
	wait->reads = 0;
}

u64
nvkm_timer_read(struct nvkm_timer *tmr)
{