Commit e4f90a35 authored by Ben Skeggs's avatar Ben Skeggs

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

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent a31e24a7
......@@ -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)
......
......@@ -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)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment