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',
*/
#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)
*/
#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)
{