1b7019ac5SIlia Mirkin /* SPDX-License-Identifier: MIT */
29e79a853SBen Skeggs #ifndef __NVKM_TIMER_H__
39e79a853SBen Skeggs #define __NVKM_TIMER_H__
4c39f472eSBen Skeggs #include <core/subdev.h>
5c39f472eSBen Skeggs
69e79a853SBen Skeggs struct nvkm_alarm {
7c39f472eSBen Skeggs struct list_head head;
8b4e382caSBen Skeggs struct list_head exec;
9c39f472eSBen Skeggs u64 timestamp;
109e79a853SBen Skeggs void (*func)(struct nvkm_alarm *);
11c39f472eSBen Skeggs };
12c39f472eSBen Skeggs
13c39f472eSBen Skeggs static inline void
nvkm_alarm_init(struct nvkm_alarm * alarm,void (* func)(struct nvkm_alarm *))1431649ecfSBen Skeggs nvkm_alarm_init(struct nvkm_alarm *alarm, void (*func)(struct nvkm_alarm *))
15c39f472eSBen Skeggs {
16c39f472eSBen Skeggs INIT_LIST_HEAD(&alarm->head);
17c39f472eSBen Skeggs alarm->func = func;
18c39f472eSBen Skeggs }
19c39f472eSBen Skeggs
2031649ecfSBen Skeggs struct nvkm_timer {
2131649ecfSBen Skeggs const struct nvkm_timer_func *func;
2231649ecfSBen Skeggs struct nvkm_subdev subdev;
2331649ecfSBen Skeggs
2431649ecfSBen Skeggs struct list_head alarms;
2531649ecfSBen Skeggs spinlock_t lock;
2631649ecfSBen Skeggs };
2731649ecfSBen Skeggs
2831649ecfSBen Skeggs u64 nvkm_timer_read(struct nvkm_timer *);
2931649ecfSBen Skeggs void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *);
30c39f472eSBen Skeggs
31e4f90a35SBen Skeggs struct nvkm_timer_wait {
32e4f90a35SBen Skeggs struct nvkm_timer *tmr;
33e4f90a35SBen Skeggs u64 limit;
34e4f90a35SBen Skeggs u64 time0;
35e4f90a35SBen Skeggs u64 time1;
36e4f90a35SBen Skeggs int reads;
37e4f90a35SBen Skeggs };
38e4f90a35SBen Skeggs
39e4f90a35SBen Skeggs void nvkm_timer_wait_init(struct nvkm_device *, u64 nsec,
40e4f90a35SBen Skeggs struct nvkm_timer_wait *);
41e4f90a35SBen Skeggs s64 nvkm_timer_wait_test(struct nvkm_timer_wait *);
42e4f90a35SBen Skeggs
4356f67dc1SBen Skeggs /* Delay based on GPU time (ie. PTIMER).
4456f67dc1SBen Skeggs *
4556f67dc1SBen Skeggs * Will return -ETIMEDOUT unless the loop was terminated with 'break',
4656f67dc1SBen Skeggs * where it will return the number of nanoseconds taken instead.
4756f67dc1SBen Skeggs *
4856f67dc1SBen Skeggs * NVKM_DELAY can be passed for 'cond' to disable the timeout warning,
4956f67dc1SBen Skeggs * which is useful for unconditional delay loops.
5056f67dc1SBen Skeggs */
5156f67dc1SBen Skeggs #define NVKM_DELAY _warn = false;
5256f67dc1SBen Skeggs #define nvkm_nsec(d,n,cond...) ({ \
53e4f90a35SBen Skeggs struct nvkm_timer_wait _wait; \
5456f67dc1SBen Skeggs bool _warn = true; \
55e4f90a35SBen Skeggs s64 _taken = 0; \
5656f67dc1SBen Skeggs \
57e4f90a35SBen Skeggs nvkm_timer_wait_init((d), (n), &_wait); \
5856f67dc1SBen Skeggs do { \
5956f67dc1SBen Skeggs cond \
60e4f90a35SBen Skeggs } while ((_taken = nvkm_timer_wait_test(&_wait)) >= 0); \
6156f67dc1SBen Skeggs \
62e4f90a35SBen Skeggs if (_warn && _taken < 0) \
63e4f90a35SBen Skeggs dev_WARN(_wait.tmr->subdev.device->dev, "timeout\n"); \
6456f67dc1SBen Skeggs _taken; \
6556f67dc1SBen Skeggs })
66804f5705STimur Tabi #define nvkm_usec(d, u, cond...) nvkm_nsec((d), (u) * 1000ULL, ##cond)
67804f5705STimur Tabi #define nvkm_msec(d, m, cond...) nvkm_usec((d), (m) * 1000ULL, ##cond)
6856f67dc1SBen Skeggs
69542f60dcSAlexandre Courbot #define nvkm_wait_nsec(d,n,addr,mask,data) \
70542f60dcSAlexandre Courbot nvkm_nsec(d, n, \
71542f60dcSAlexandre Courbot if ((nvkm_rd32(d, (addr)) & (mask)) == (data)) \
72542f60dcSAlexandre Courbot break; \
73542f60dcSAlexandre Courbot )
74542f60dcSAlexandre Courbot #define nvkm_wait_usec(d,u,addr,mask,data) \
75542f60dcSAlexandre Courbot nvkm_wait_nsec((d), (u) * 1000, (addr), (mask), (data))
76542f60dcSAlexandre Courbot #define nvkm_wait_msec(d,m,addr,mask,data) \
77542f60dcSAlexandre Courbot nvkm_wait_usec((d), (m) * 1000, (addr), (mask), (data))
78542f60dcSAlexandre Courbot
79*9aad54d5SBen Skeggs int nv04_timer_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_timer **);
80*9aad54d5SBen Skeggs int nv40_timer_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_timer **);
81*9aad54d5SBen Skeggs int nv41_timer_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_timer **);
82*9aad54d5SBen Skeggs int gk20a_timer_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_timer **);
83c39f472eSBen Skeggs #endif
84