xref: /linux/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
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