|
@@ -16,12 +16,63 @@ nvkm_alarm_init(struct nvkm_alarm *alarm,
|
|
|
alarm->func = func;
|
|
|
}
|
|
|
|
|
|
-bool nvkm_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
|
|
|
-bool nvkm_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
|
|
|
-bool nvkm_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
|
|
|
void nvkm_timer_alarm(void *, u32 nsec, struct nvkm_alarm *);
|
|
|
void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *);
|
|
|
|
|
|
+/* Delay based on GPU time (ie. PTIMER).
|
|
|
+ *
|
|
|
+ * Will return -ETIMEDOUT unless the loop was terminated with 'break',
|
|
|
+ * where it will return the number of nanoseconds taken instead.
|
|
|
+ *
|
|
|
+ * NVKM_DELAY can be passed for 'cond' to disable the timeout warning,
|
|
|
+ * which is useful for unconditional delay loops.
|
|
|
+ */
|
|
|
+#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 = _tmr->read(_tmr); \
|
|
|
+ s64 _taken = 0; \
|
|
|
+ bool _warn = true; \
|
|
|
+ \
|
|
|
+ do { \
|
|
|
+ cond \
|
|
|
+ } while (_taken = _tmr->read(_tmr) - _time0, _taken < _nsecs); \
|
|
|
+ \
|
|
|
+ if (_taken >= _nsecs) { \
|
|
|
+ if (_warn) { \
|
|
|
+ dev_warn(_device->dev, "timeout at %s:%d/%s()!\n", \
|
|
|
+ __FILE__, __LINE__, __func__); \
|
|
|
+ } \
|
|
|
+ _taken = -ETIMEDOUT; \
|
|
|
+ } \
|
|
|
+ _taken; \
|
|
|
+})
|
|
|
+#define nvkm_usec(d,u,cond...) nvkm_nsec((d), (u) * 1000, ##cond)
|
|
|
+#define nvkm_msec(d,m,cond...) nvkm_usec((d), (m) * 1000, ##cond)
|
|
|
+
|
|
|
+#define nvkm_timer_wait_eq(o,n,a,m,v) ({ \
|
|
|
+ struct nvkm_device *__device = nv_device(o); \
|
|
|
+ nvkm_nsec(__device, (n), \
|
|
|
+ if ((nvkm_rd32(__device, (a)) & (m)) == (v)) \
|
|
|
+ break; \
|
|
|
+ ) >= 0; \
|
|
|
+})
|
|
|
+#define nvkm_timer_wait_ne(o,n,a,m,v) ({ \
|
|
|
+ struct nvkm_device *__device = nv_device(o); \
|
|
|
+ nvkm_nsec(__device, (n), \
|
|
|
+ if ((nvkm_rd32(__device, (a)) & (m)) != (v)) \
|
|
|
+ break; \
|
|
|
+ ) >= 0; \
|
|
|
+})
|
|
|
+#define nvkm_timer_wait_cb(o,n,c,d) ({ \
|
|
|
+ struct nvkm_device *__device = nv_device(o); \
|
|
|
+ nvkm_nsec(__device, (n), \
|
|
|
+ if (c(d)) \
|
|
|
+ break; \
|
|
|
+ ) >= 0; \
|
|
|
+})
|
|
|
+
|
|
|
#define NV_WAIT_DEFAULT 2000000000ULL
|
|
|
#define nv_wait(o,a,m,v) \
|
|
|
nvkm_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v))
|