1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "priv.h"
25
26u64
27nvkm_timer_read(struct nvkm_timer *tmr)
28{
29 return tmr->func->read(tmr);
30}
31
32void
33nvkm_timer_alarm_trigger(struct nvkm_timer *tmr)
34{
35 struct nvkm_alarm *alarm, *atemp;
36 unsigned long flags;
37 LIST_HEAD(exec);
38
39
40 spin_lock_irqsave(&tmr->lock, flags);
41 list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) {
42
43 if (alarm->timestamp > nvkm_timer_read(tmr)) {
44
45 tmr->func->alarm_init(tmr, alarm->timestamp);
46 if (alarm->timestamp > nvkm_timer_read(tmr))
47 break;
48 }
49
50
51
52
53 list_del_init(&alarm->head);
54 list_add(&alarm->exec, &exec);
55 }
56
57
58 if (list_empty(&tmr->alarms))
59 tmr->func->alarm_fini(tmr);
60 spin_unlock_irqrestore(&tmr->lock, flags);
61
62
63 list_for_each_entry_safe(alarm, atemp, &exec, exec) {
64 list_del(&alarm->exec);
65 alarm->func(alarm);
66 }
67}
68
69void
70nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm)
71{
72 struct nvkm_alarm *list;
73 unsigned long flags;
74
75
76
77
78
79
80 spin_lock_irqsave(&tmr->lock, flags);
81 list_del_init(&alarm->head);
82
83 if (nsec) {
84
85 alarm->timestamp = nvkm_timer_read(tmr) + nsec;
86 list_for_each_entry(list, &tmr->alarms, head) {
87 if (list->timestamp > alarm->timestamp)
88 break;
89 }
90
91 list_add_tail(&alarm->head, &list->head);
92
93
94 list = list_first_entry(&tmr->alarms, typeof(*list), head);
95 if (list == alarm) {
96 tmr->func->alarm_init(tmr, alarm->timestamp);
97
98
99
100
101
102 WARN_ON(alarm->timestamp <= nvkm_timer_read(tmr));
103 }
104 }
105 spin_unlock_irqrestore(&tmr->lock, flags);
106}
107
108static void
109nvkm_timer_intr(struct nvkm_subdev *subdev)
110{
111 struct nvkm_timer *tmr = nvkm_timer(subdev);
112 tmr->func->intr(tmr);
113}
114
115static int
116nvkm_timer_fini(struct nvkm_subdev *subdev, bool suspend)
117{
118 struct nvkm_timer *tmr = nvkm_timer(subdev);
119 tmr->func->alarm_fini(tmr);
120 return 0;
121}
122
123static int
124nvkm_timer_init(struct nvkm_subdev *subdev)
125{
126 struct nvkm_timer *tmr = nvkm_timer(subdev);
127 if (tmr->func->init)
128 tmr->func->init(tmr);
129 tmr->func->time(tmr, ktime_to_ns(ktime_get()));
130 nvkm_timer_alarm_trigger(tmr);
131 return 0;
132}
133
134static void *
135nvkm_timer_dtor(struct nvkm_subdev *subdev)
136{
137 return nvkm_timer(subdev);
138}
139
140static const struct nvkm_subdev_func
141nvkm_timer = {
142 .dtor = nvkm_timer_dtor,
143 .init = nvkm_timer_init,
144 .fini = nvkm_timer_fini,
145 .intr = nvkm_timer_intr,
146};
147
148int
149nvkm_timer_new_(const struct nvkm_timer_func *func, struct nvkm_device *device,
150 int index, struct nvkm_timer **ptmr)
151{
152 struct nvkm_timer *tmr;
153
154 if (!(tmr = *ptmr = kzalloc(sizeof(*tmr), GFP_KERNEL)))
155 return -ENOMEM;
156
157 nvkm_subdev_ctor(&nvkm_timer, device, index, &tmr->subdev);
158 tmr->func = func;
159 INIT_LIST_HEAD(&tmr->alarms);
160 spin_lock_init(&tmr->lock);
161 return 0;
162}
163