1 #ifndef __NVKM_TIMER_H__
2 #define __NVKM_TIMER_H__
3 #include <core/subdev.h>
4 
5 struct nvkm_alarm {
6 	struct list_head head;
7 	u64 timestamp;
8 	void (*func)(struct nvkm_alarm *);
9 };
10 
11 static inline void
12 nvkm_alarm_init(struct nvkm_alarm *alarm,
13 		   void (*func)(struct nvkm_alarm *))
14 {
15 	INIT_LIST_HEAD(&alarm->head);
16 	alarm->func = func;
17 }
18 
19 void nvkm_timer_alarm(void *, u32 nsec, struct nvkm_alarm *);
20 void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *);
21 
22 /* Delay based on GPU time (ie. PTIMER).
23  *
24  * Will return -ETIMEDOUT unless the loop was terminated with 'break',
25  * where it will return the number of nanoseconds taken instead.
26  *
27  * NVKM_DELAY can be passed for 'cond' to disable the timeout warning,
28  * which is useful for unconditional delay loops.
29  */
30 #define NVKM_DELAY _warn = false;
31 #define nvkm_nsec(d,n,cond...) ({                                              \
32 	struct nvkm_device *_device = (d);                                     \
33 	struct nvkm_timer *_tmr = _device->timer;                              \
34 	u64 _nsecs = (n), _time0 = _tmr->read(_tmr);                           \
35 	s64 _taken = 0;                                                        \
36 	bool _warn = true;                                                    \
37                                                                                \
38 	do {                                                                   \
39 		cond                                                           \
40 	} while (_taken = _tmr->read(_tmr) - _time0, _taken < _nsecs);         \
41                                                                                \
42 	if (_taken >= _nsecs) {                                                \
43 		if (_warn) {                                                   \
44 			dev_warn(_device->dev, "timeout at %s:%d/%s()!\n",     \
45 				 __FILE__, __LINE__, __func__);                \
46 		}                                                              \
47 		_taken = -ETIMEDOUT;                                           \
48 	}                                                                      \
49 	_taken;                                                                \
50 })
51 #define nvkm_usec(d,u,cond...) nvkm_nsec((d), (u) * 1000, ##cond)
52 #define nvkm_msec(d,m,cond...) nvkm_usec((d), (m) * 1000, ##cond)
53 
54 struct nvkm_timer {
55 	struct nvkm_subdev subdev;
56 	u64  (*read)(struct nvkm_timer *);
57 	void (*alarm)(struct nvkm_timer *, u64 time, struct nvkm_alarm *);
58 	void (*alarm_cancel)(struct nvkm_timer *, struct nvkm_alarm *);
59 };
60 
61 static inline struct nvkm_timer *
62 nvkm_timer(void *obj)
63 {
64 	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_TIMER);
65 }
66 
67 #define nvkm_timer_create(p,e,o,d)                                          \
68 	nvkm_subdev_create_((p), (e), (o), 0, "PTIMER", "timer",            \
69 			       sizeof(**d), (void **)d)
70 #define nvkm_timer_destroy(p)                                               \
71 	nvkm_subdev_destroy(&(p)->subdev)
72 #define nvkm_timer_init(p)                                                  \
73 	nvkm_subdev_init(&(p)->subdev)
74 #define nvkm_timer_fini(p,s)                                                \
75 	nvkm_subdev_fini(&(p)->subdev, (s))
76 
77 int nvkm_timer_create_(struct nvkm_object *, struct nvkm_engine *,
78 			  struct nvkm_oclass *, int size, void **);
79 
80 extern struct nvkm_oclass nv04_timer_oclass;
81 extern struct nvkm_oclass gk20a_timer_oclass;
82 #endif
83