This source file includes following definitions.
- host1x_syncpt_base_request
- host1x_syncpt_base_free
- host1x_syncpt_alloc
- host1x_syncpt_id
- host1x_syncpt_incr_max
- host1x_syncpt_restore
- host1x_syncpt_save
- host1x_syncpt_load
- host1x_syncpt_load_wait_base
- host1x_syncpt_incr
- syncpt_load_min_is_expired
- host1x_syncpt_wait
- host1x_syncpt_is_expired
- host1x_syncpt_init
- host1x_syncpt_request
- host1x_syncpt_free
- host1x_syncpt_deinit
- host1x_syncpt_read_max
- host1x_syncpt_read_min
- host1x_syncpt_read
- host1x_syncpt_nb_pts
- host1x_syncpt_nb_bases
- host1x_syncpt_nb_mlocks
- host1x_syncpt_get
- host1x_syncpt_get_base
- host1x_syncpt_base_id
1
2
3
4
5
6
7
8 #include <linux/module.h>
9 #include <linux/device.h>
10 #include <linux/slab.h>
11
12 #include <trace/events/host1x.h>
13
14 #include "syncpt.h"
15 #include "dev.h"
16 #include "intr.h"
17 #include "debug.h"
18
19 #define SYNCPT_CHECK_PERIOD (2 * HZ)
20 #define MAX_STUCK_CHECK_COUNT 15
21
22 static struct host1x_syncpt_base *
23 host1x_syncpt_base_request(struct host1x *host)
24 {
25 struct host1x_syncpt_base *bases = host->bases;
26 unsigned int i;
27
28 for (i = 0; i < host->info->nb_bases; i++)
29 if (!bases[i].requested)
30 break;
31
32 if (i >= host->info->nb_bases)
33 return NULL;
34
35 bases[i].requested = true;
36 return &bases[i];
37 }
38
39 static void host1x_syncpt_base_free(struct host1x_syncpt_base *base)
40 {
41 if (base)
42 base->requested = false;
43 }
44
45 static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
46 struct host1x_client *client,
47 unsigned long flags)
48 {
49 struct host1x_syncpt *sp = host->syncpt;
50 unsigned int i;
51 char *name;
52
53 mutex_lock(&host->syncpt_mutex);
54
55 for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++)
56 ;
57
58 if (i >= host->info->nb_pts)
59 goto unlock;
60
61 if (flags & HOST1X_SYNCPT_HAS_BASE) {
62 sp->base = host1x_syncpt_base_request(host);
63 if (!sp->base)
64 goto unlock;
65 }
66
67 name = kasprintf(GFP_KERNEL, "%02u-%s", sp->id,
68 client ? dev_name(client->dev) : NULL);
69 if (!name)
70 goto free_base;
71
72 sp->client = client;
73 sp->name = name;
74
75 if (flags & HOST1X_SYNCPT_CLIENT_MANAGED)
76 sp->client_managed = true;
77 else
78 sp->client_managed = false;
79
80 mutex_unlock(&host->syncpt_mutex);
81 return sp;
82
83 free_base:
84 host1x_syncpt_base_free(sp->base);
85 sp->base = NULL;
86 unlock:
87 mutex_unlock(&host->syncpt_mutex);
88 return NULL;
89 }
90
91
92
93
94
95
96
97
98
99 u32 host1x_syncpt_id(struct host1x_syncpt *sp)
100 {
101 return sp->id;
102 }
103 EXPORT_SYMBOL(host1x_syncpt_id);
104
105
106
107
108
109
110 u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)
111 {
112 return (u32)atomic_add_return(incrs, &sp->max_val);
113 }
114 EXPORT_SYMBOL(host1x_syncpt_incr_max);
115
116
117
118
119 void host1x_syncpt_restore(struct host1x *host)
120 {
121 struct host1x_syncpt *sp_base = host->syncpt;
122 unsigned int i;
123
124 for (i = 0; i < host1x_syncpt_nb_pts(host); i++)
125 host1x_hw_syncpt_restore(host, sp_base + i);
126
127 for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
128 host1x_hw_syncpt_restore_wait_base(host, sp_base + i);
129
130 wmb();
131 }
132
133
134
135
136
137 void host1x_syncpt_save(struct host1x *host)
138 {
139 struct host1x_syncpt *sp_base = host->syncpt;
140 unsigned int i;
141
142 for (i = 0; i < host1x_syncpt_nb_pts(host); i++) {
143 if (host1x_syncpt_client_managed(sp_base + i))
144 host1x_hw_syncpt_load(host, sp_base + i);
145 else
146 WARN_ON(!host1x_syncpt_idle(sp_base + i));
147 }
148
149 for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
150 host1x_hw_syncpt_load_wait_base(host, sp_base + i);
151 }
152
153
154
155
156
157 u32 host1x_syncpt_load(struct host1x_syncpt *sp)
158 {
159 u32 val;
160
161 val = host1x_hw_syncpt_load(sp->host, sp);
162 trace_host1x_syncpt_load_min(sp->id, val);
163
164 return val;
165 }
166
167
168
169
170 u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp)
171 {
172 host1x_hw_syncpt_load_wait_base(sp->host, sp);
173
174 return sp->base_val;
175 }
176
177
178
179
180
181 int host1x_syncpt_incr(struct host1x_syncpt *sp)
182 {
183 return host1x_hw_syncpt_cpu_incr(sp->host, sp);
184 }
185 EXPORT_SYMBOL(host1x_syncpt_incr);
186
187
188
189
190
191 static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh)
192 {
193 host1x_hw_syncpt_load(sp->host, sp);
194
195 return host1x_syncpt_is_expired(sp, thresh);
196 }
197
198
199
200
201
202
203
204
205 int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
206 u32 *value)
207 {
208 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
209 void *ref;
210 struct host1x_waitlist *waiter;
211 int err = 0, check_count = 0;
212 u32 val;
213
214 if (value)
215 *value = 0;
216
217
218 if (host1x_syncpt_is_expired(sp, thresh)) {
219 if (value)
220 *value = host1x_syncpt_load(sp);
221
222 return 0;
223 }
224
225
226 val = host1x_hw_syncpt_load(sp->host, sp);
227 if (host1x_syncpt_is_expired(sp, thresh)) {
228 if (value)
229 *value = val;
230
231 goto done;
232 }
233
234 if (!timeout) {
235 err = -EAGAIN;
236 goto done;
237 }
238
239
240 waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
241 if (!waiter) {
242 err = -ENOMEM;
243 goto done;
244 }
245
246
247 err = host1x_intr_add_action(sp->host, sp, thresh,
248 HOST1X_INTR_ACTION_WAKEUP_INTERRUPTIBLE,
249 &wq, waiter, &ref);
250 if (err)
251 goto done;
252
253 err = -EAGAIN;
254
255 if (timeout < 0)
256 timeout = LONG_MAX;
257
258
259 while (timeout) {
260 long check = min_t(long, SYNCPT_CHECK_PERIOD, timeout);
261 int remain;
262
263 remain = wait_event_interruptible_timeout(wq,
264 syncpt_load_min_is_expired(sp, thresh),
265 check);
266 if (remain > 0 || host1x_syncpt_is_expired(sp, thresh)) {
267 if (value)
268 *value = host1x_syncpt_load(sp);
269
270 err = 0;
271
272 break;
273 }
274
275 if (remain < 0) {
276 err = remain;
277 break;
278 }
279
280 timeout -= check;
281
282 if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) {
283 dev_warn(sp->host->dev,
284 "%s: syncpoint id %u (%s) stuck waiting %d, timeout=%ld\n",
285 current->comm, sp->id, sp->name,
286 thresh, timeout);
287
288 host1x_debug_dump_syncpts(sp->host);
289
290 if (check_count == MAX_STUCK_CHECK_COUNT)
291 host1x_debug_dump(sp->host);
292
293 check_count++;
294 }
295 }
296
297 host1x_intr_put_ref(sp->host, sp->id, ref);
298
299 done:
300 return err;
301 }
302 EXPORT_SYMBOL(host1x_syncpt_wait);
303
304
305
306
307 bool host1x_syncpt_is_expired(struct host1x_syncpt *sp, u32 thresh)
308 {
309 u32 current_val;
310 u32 future_val;
311
312 smp_rmb();
313
314 current_val = (u32)atomic_read(&sp->min_val);
315 future_val = (u32)atomic_read(&sp->max_val);
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 if (!host1x_syncpt_client_managed(sp))
360 return future_val - thresh >= current_val - thresh;
361 else
362 return (s32)(current_val - thresh) >= 0;
363 }
364
365 int host1x_syncpt_init(struct host1x *host)
366 {
367 struct host1x_syncpt_base *bases;
368 struct host1x_syncpt *syncpt;
369 unsigned int i;
370
371 syncpt = devm_kcalloc(host->dev, host->info->nb_pts, sizeof(*syncpt),
372 GFP_KERNEL);
373 if (!syncpt)
374 return -ENOMEM;
375
376 bases = devm_kcalloc(host->dev, host->info->nb_bases, sizeof(*bases),
377 GFP_KERNEL);
378 if (!bases)
379 return -ENOMEM;
380
381 for (i = 0; i < host->info->nb_pts; i++) {
382 syncpt[i].id = i;
383 syncpt[i].host = host;
384
385
386
387
388
389
390 host1x_hw_syncpt_assign_to_channel(host, &syncpt[i], NULL);
391 }
392
393 for (i = 0; i < host->info->nb_bases; i++)
394 bases[i].id = i;
395
396 mutex_init(&host->syncpt_mutex);
397 host->syncpt = syncpt;
398 host->bases = bases;
399
400 host1x_syncpt_restore(host);
401 host1x_hw_syncpt_enable_protection(host);
402
403
404 host->nop_sp = host1x_syncpt_alloc(host, NULL, 0);
405 if (!host->nop_sp)
406 return -ENOMEM;
407
408 return 0;
409 }
410
411
412
413
414
415
416
417
418
419
420
421 struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client,
422 unsigned long flags)
423 {
424 struct host1x *host = dev_get_drvdata(client->parent->parent);
425
426 return host1x_syncpt_alloc(host, client, flags);
427 }
428 EXPORT_SYMBOL(host1x_syncpt_request);
429
430
431
432
433
434
435
436
437
438
439
440 void host1x_syncpt_free(struct host1x_syncpt *sp)
441 {
442 if (!sp)
443 return;
444
445 mutex_lock(&sp->host->syncpt_mutex);
446
447 host1x_syncpt_base_free(sp->base);
448 kfree(sp->name);
449 sp->base = NULL;
450 sp->client = NULL;
451 sp->name = NULL;
452 sp->client_managed = false;
453
454 mutex_unlock(&sp->host->syncpt_mutex);
455 }
456 EXPORT_SYMBOL(host1x_syncpt_free);
457
458 void host1x_syncpt_deinit(struct host1x *host)
459 {
460 struct host1x_syncpt *sp = host->syncpt;
461 unsigned int i;
462
463 for (i = 0; i < host->info->nb_pts; i++, sp++)
464 kfree(sp->name);
465 }
466
467
468
469
470
471
472
473
474 u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
475 {
476 smp_rmb();
477
478 return (u32)atomic_read(&sp->max_val);
479 }
480 EXPORT_SYMBOL(host1x_syncpt_read_max);
481
482
483
484
485
486
487
488
489 u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
490 {
491 smp_rmb();
492
493 return (u32)atomic_read(&sp->min_val);
494 }
495 EXPORT_SYMBOL(host1x_syncpt_read_min);
496
497
498
499
500
501 u32 host1x_syncpt_read(struct host1x_syncpt *sp)
502 {
503 return host1x_syncpt_load(sp);
504 }
505 EXPORT_SYMBOL(host1x_syncpt_read);
506
507 unsigned int host1x_syncpt_nb_pts(struct host1x *host)
508 {
509 return host->info->nb_pts;
510 }
511
512 unsigned int host1x_syncpt_nb_bases(struct host1x *host)
513 {
514 return host->info->nb_bases;
515 }
516
517 unsigned int host1x_syncpt_nb_mlocks(struct host1x *host)
518 {
519 return host->info->nb_mlocks;
520 }
521
522
523
524
525
526
527 struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id)
528 {
529 if (id >= host->info->nb_pts)
530 return NULL;
531
532 return host->syncpt + id;
533 }
534 EXPORT_SYMBOL(host1x_syncpt_get);
535
536
537
538
539
540 struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp)
541 {
542 return sp ? sp->base : NULL;
543 }
544 EXPORT_SYMBOL(host1x_syncpt_get_base);
545
546
547
548
549
550 u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base)
551 {
552 return base->id;
553 }
554 EXPORT_SYMBOL(host1x_syncpt_base_id);