740502bf8714982986cb00ca100ae4978201d2ea
[linux-2.6.git] / drivers / video / tegra / host / nvhost_syncpt.c
1 /*
2  * drivers/video/tegra/host/nvhost_syncpt.c
3  *
4  * Tegra Graphics Host Syncpoints
5  *
6  * Copyright (c) 2010-2012, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/nvhost_ioctl.h>
22 #include <linux/platform_device.h>
23 #include <linux/slab.h>
24 #include <linux/stat.h>
25 #include <trace/events/nvhost.h>
26 #include "nvhost_syncpt.h"
27 #include "nvhost_acm.h"
28 #include "dev.h"
29 #include "chip_support.h"
30
31 #define MAX_SYNCPT_LENGTH       5
32
33 /* Name of sysfs node for min and max value */
34 static const char *min_name = "min";
35 static const char *max_name = "max";
36
37 /**
38  * Resets syncpoint and waitbase values to sw shadows
39  */
40 void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
41 {
42         u32 i;
43         BUG_ON(!(syncpt_op().reset && syncpt_op().reset_wait_base));
44
45         for (i = 0; i < nvhost_syncpt_nb_pts(sp); i++)
46                 syncpt_op().reset(sp, i);
47         for (i = 0; i < nvhost_syncpt_nb_bases(sp); i++)
48                 syncpt_op().reset_wait_base(sp, i);
49         wmb();
50 }
51
52 /**
53  * Resets syncpoint and waitbase values of a
54  * single client to sw shadows
55  */
56 void nvhost_syncpt_reset_client(struct platform_device *pdev)
57 {
58         struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
59         struct nvhost_master *nvhost_master = nvhost_get_host(pdev);
60         u32 id;
61
62         BUG_ON(!(syncpt_op().reset && syncpt_op().reset_wait_base));
63
64         for_each_set_bit(id, (unsigned long *)&pdata->syncpts, BITS_PER_LONG)
65                 syncpt_op().reset(&nvhost_master->syncpt, id);
66         for_each_set_bit(id, (unsigned long *)&pdata->waitbases, BITS_PER_LONG)
67                 syncpt_op().reset_wait_base(&nvhost_master->syncpt, id);
68         wmb();
69 }
70
71
72 /**
73  * Updates sw shadow state for client managed registers
74  */
75 void nvhost_syncpt_save(struct nvhost_syncpt *sp)
76 {
77         u32 i;
78         BUG_ON(!(syncpt_op().update_min && syncpt_op().read_wait_base));
79
80         for (i = 0; i < nvhost_syncpt_nb_pts(sp); i++) {
81                 if (nvhost_syncpt_client_managed(sp, i))
82                         syncpt_op().update_min(sp, i);
83                 else
84                         BUG_ON(!nvhost_syncpt_min_eq_max(sp, i));
85         }
86
87         for (i = 0; i < nvhost_syncpt_nb_bases(sp); i++)
88                 syncpt_op().read_wait_base(sp, i);
89 }
90
91 /**
92  * Updates the last value read from hardware.
93  */
94 u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
95 {
96         u32 val;
97
98         BUG_ON(!syncpt_op().update_min);
99
100         val = syncpt_op().update_min(sp, id);
101         trace_nvhost_syncpt_update_min(id, val);
102
103         return val;
104 }
105
106 /**
107  * Get the current syncpoint value
108  */
109 u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
110 {
111         u32 val;
112         BUG_ON(!syncpt_op().update_min);
113         nvhost_module_busy(syncpt_to_dev(sp)->dev);
114         val = syncpt_op().update_min(sp, id);
115         nvhost_module_idle(syncpt_to_dev(sp)->dev);
116         return val;
117 }
118
119 /**
120  * Get the current syncpoint base
121  */
122 u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
123 {
124         u32 val;
125         BUG_ON(!syncpt_op().read_wait_base);
126         nvhost_module_busy(syncpt_to_dev(sp)->dev);
127         syncpt_op().read_wait_base(sp, id);
128         val = sp->base_val[id];
129         nvhost_module_idle(syncpt_to_dev(sp)->dev);
130         return val;
131 }
132
133 /**
134  * Write a cpu syncpoint increment to the hardware, without touching
135  * the cache. Caller is responsible for host being powered.
136  */
137 void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
138 {
139         BUG_ON(!syncpt_op().cpu_incr);
140         syncpt_op().cpu_incr(sp, id);
141 }
142
143 /**
144  * Increment syncpoint value from cpu, updating cache
145  */
146 void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id)
147 {
148         if (nvhost_syncpt_client_managed(sp, id))
149                 nvhost_syncpt_incr_max(sp, id, 1);
150         nvhost_module_busy(syncpt_to_dev(sp)->dev);
151         nvhost_syncpt_cpu_incr(sp, id);
152         nvhost_module_idle(syncpt_to_dev(sp)->dev);
153 }
154
155 /**
156  * Updated sync point form hardware, and returns true if syncpoint is expired,
157  * false if we may need to wait
158  */
159 static bool syncpt_update_min_is_expired(
160         struct nvhost_syncpt *sp,
161         u32 id,
162         u32 thresh)
163 {
164         syncpt_op().update_min(sp, id);
165         return nvhost_syncpt_is_expired(sp, id, thresh);
166 }
167
168 /**
169  * Main entrypoint for syncpoint value waits.
170  */
171 int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
172                         u32 thresh, u32 timeout, u32 *value)
173 {
174         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
175         void *ref;
176         void *waiter;
177         int err = 0, check_count = 0, low_timeout = 0;
178         u32 val;
179
180         if (value)
181                 *value = 0;
182
183         /* first check cache */
184         if (nvhost_syncpt_is_expired(sp, id, thresh)) {
185                 if (value)
186                         *value = nvhost_syncpt_read_min(sp, id);
187                 return 0;
188         }
189
190         /* keep host alive */
191         nvhost_module_busy(syncpt_to_dev(sp)->dev);
192
193         /* try to read from register */
194         val = syncpt_op().update_min(sp, id);
195         if (nvhost_syncpt_is_expired(sp, id, thresh)) {
196                 if (value)
197                         *value = val;
198                 goto done;
199         }
200
201         if (!timeout) {
202                 err = -EAGAIN;
203                 goto done;
204         }
205
206         /* schedule a wakeup when the syncpoint value is reached */
207         waiter = nvhost_intr_alloc_waiter();
208         if (!waiter) {
209                 err = -ENOMEM;
210                 goto done;
211         }
212
213         err = nvhost_intr_add_action(&(syncpt_to_dev(sp)->intr), id, thresh,
214                                 NVHOST_INTR_ACTION_WAKEUP_INTERRUPTIBLE, &wq,
215                                 waiter,
216                                 &ref);
217         if (err)
218                 goto done;
219
220         err = -EAGAIN;
221         /* Caller-specified timeout may be impractically low */
222         if (timeout < SYNCPT_CHECK_PERIOD)
223                 low_timeout = timeout;
224
225         /* wait for the syncpoint, or timeout, or signal */
226         while (timeout) {
227                 u32 check = min_t(u32, SYNCPT_CHECK_PERIOD, timeout);
228                 int remain = wait_event_interruptible_timeout(wq,
229                                 syncpt_update_min_is_expired(sp, id, thresh),
230                                 check);
231                 if (remain > 0 || nvhost_syncpt_is_expired(sp, id, thresh)) {
232                         if (value)
233                                 *value = nvhost_syncpt_read_min(sp, id);
234                         err = 0;
235                         break;
236                 }
237                 if (remain < 0) {
238                         err = remain;
239                         break;
240                 }
241                 if (timeout != NVHOST_NO_TIMEOUT)
242                         timeout -= check;
243                 if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) {
244                         dev_warn(&syncpt_to_dev(sp)->dev->dev,
245                                 "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%d\n",
246                                  current->comm, id, syncpt_op().name(sp, id),
247                                  thresh, timeout);
248                         syncpt_op().debug(sp);
249                         if (check_count == MAX_STUCK_CHECK_COUNT) {
250                                 if (low_timeout) {
251                                         dev_warn(&syncpt_to_dev(sp)->dev->dev,
252                                                 "is timeout %d too low?\n",
253                                                 low_timeout);
254                                 }
255                                 nvhost_debug_dump(syncpt_to_dev(sp));
256                         }
257                         check_count++;
258                 }
259         }
260         nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), id, ref);
261
262 done:
263         nvhost_module_idle(syncpt_to_dev(sp)->dev);
264         return err;
265 }
266
267 /**
268  * Returns true if syncpoint is expired, false if we may need to wait
269  */
270 bool nvhost_syncpt_is_expired(
271         struct nvhost_syncpt *sp,
272         u32 id,
273         u32 thresh)
274 {
275         u32 current_val;
276         u32 future_val;
277         smp_rmb();
278         current_val = (u32)atomic_read(&sp->min_val[id]);
279         future_val = (u32)atomic_read(&sp->max_val[id]);
280
281         /* Note the use of unsigned arithmetic here (mod 1<<32).
282          *
283          * c = current_val = min_val    = the current value of the syncpoint.
284          * t = thresh                   = the value we are checking
285          * f = future_val  = max_val    = the value c will reach when all
286          *                                outstanding increments have completed.
287          *
288          * Note that c always chases f until it reaches f.
289          *
290          * Dtf = (f - t)
291          * Dtc = (c - t)
292          *
293          *  Consider all cases:
294          *
295          *      A) .....c..t..f.....    Dtf < Dtc       need to wait
296          *      B) .....c.....f..t..    Dtf > Dtc       expired
297          *      C) ..t..c.....f.....    Dtf > Dtc       expired    (Dct very large)
298          *
299          *  Any case where f==c: always expired (for any t).    Dtf == Dcf
300          *  Any case where t==c: always expired (for any f).    Dtf >= Dtc (because Dtc==0)
301          *  Any case where t==f!=c: always wait.                Dtf <  Dtc (because Dtf==0,
302          *                                                      Dtc!=0)
303          *
304          *  Other cases:
305          *
306          *      A) .....t..f..c.....    Dtf < Dtc       need to wait
307          *      A) .....f..c..t.....    Dtf < Dtc       need to wait
308          *      A) .....f..t..c.....    Dtf > Dtc       expired
309          *
310          *   So:
311          *         Dtf >= Dtc implies EXPIRED   (return true)
312          *         Dtf <  Dtc implies WAIT      (return false)
313          *
314          * Note: If t is expired then we *cannot* wait on it. We would wait
315          * forever (hang the system).
316          *
317          * Note: do NOT get clever and remove the -thresh from both sides. It
318          * is NOT the same.
319          *
320          * If future valueis zero, we have a client managed sync point. In that
321          * case we do a direct comparison.
322          */
323         if (!nvhost_syncpt_client_managed(sp, id))
324                 return future_val - thresh >= current_val - thresh;
325         else
326                 return (s32)(current_val - thresh) >= 0;
327 }
328
329 void nvhost_syncpt_debug(struct nvhost_syncpt *sp)
330 {
331         syncpt_op().debug(sp);
332 }
333
334 int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
335 {
336         struct nvhost_master *host = syncpt_to_dev(sp);
337         u32 reg;
338
339         nvhost_module_busy(host->dev);
340         reg = syncpt_op().mutex_try_lock(sp, idx);
341         if (reg) {
342                 nvhost_module_idle(host->dev);
343                 return -EBUSY;
344         }
345         atomic_inc(&sp->lock_counts[idx]);
346         return 0;
347 }
348
349 void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx)
350 {
351         syncpt_op().mutex_unlock(sp, idx);
352         nvhost_module_idle(syncpt_to_dev(sp)->dev);
353         atomic_dec(&sp->lock_counts[idx]);
354 }
355
356 /* remove a wait pointed to by patch_addr */
357 int nvhost_syncpt_patch_wait(struct nvhost_syncpt *sp, void *patch_addr)
358 {
359         return syncpt_op().patch_wait(sp, patch_addr);
360 }
361
362 /* Displays the current value of the sync point via sysfs */
363 static ssize_t syncpt_min_show(struct kobject *kobj,
364                 struct kobj_attribute *attr, char *buf)
365 {
366         struct nvhost_syncpt_attr *syncpt_attr =
367                 container_of(attr, struct nvhost_syncpt_attr, attr);
368
369         return snprintf(buf, PAGE_SIZE, "%u",
370                         nvhost_syncpt_read(&syncpt_attr->host->syncpt,
371                                 syncpt_attr->id));
372 }
373
374 static ssize_t syncpt_max_show(struct kobject *kobj,
375                 struct kobj_attribute *attr, char *buf)
376 {
377         struct nvhost_syncpt_attr *syncpt_attr =
378                 container_of(attr, struct nvhost_syncpt_attr, attr);
379
380         return snprintf(buf, PAGE_SIZE, "%u",
381                         nvhost_syncpt_read_max(&syncpt_attr->host->syncpt,
382                                 syncpt_attr->id));
383 }
384
385 int nvhost_syncpt_init(struct platform_device *dev,
386                 struct nvhost_syncpt *sp)
387 {
388         int i;
389         struct nvhost_master *host = syncpt_to_dev(sp);
390         int err = 0;
391
392         /* Allocate structs for min, max and base values */
393         sp->min_val = kzalloc(sizeof(atomic_t) * nvhost_syncpt_nb_pts(sp),
394                         GFP_KERNEL);
395         sp->max_val = kzalloc(sizeof(atomic_t) * nvhost_syncpt_nb_pts(sp),
396                         GFP_KERNEL);
397         sp->base_val = kzalloc(sizeof(u32) * nvhost_syncpt_nb_bases(sp),
398                         GFP_KERNEL);
399         sp->lock_counts =
400                 kzalloc(sizeof(atomic_t) * nvhost_syncpt_nb_mlocks(sp),
401                         GFP_KERNEL);
402
403         if (!(sp->min_val && sp->max_val && sp->base_val && sp->lock_counts)) {
404                 /* frees happen in the deinit */
405                 err = -ENOMEM;
406                 goto fail;
407         }
408
409         sp->kobj = kobject_create_and_add("syncpt", &dev->dev.kobj);
410         if (!sp->kobj) {
411                 err = -EIO;
412                 goto fail;
413         }
414
415         /* Allocate two attributes for each sync point: min and max */
416         sp->syncpt_attrs = kzalloc(sizeof(*sp->syncpt_attrs)
417                         * nvhost_syncpt_nb_pts(sp) * 2, GFP_KERNEL);
418         if (!sp->syncpt_attrs) {
419                 err = -ENOMEM;
420                 goto fail;
421         }
422
423         /* Fill in the attributes */
424         for (i = 0; i < nvhost_syncpt_nb_pts(sp); i++) {
425                 char name[MAX_SYNCPT_LENGTH];
426                 struct kobject *kobj;
427                 struct nvhost_syncpt_attr *min = &sp->syncpt_attrs[i*2];
428                 struct nvhost_syncpt_attr *max = &sp->syncpt_attrs[i*2+1];
429
430                 /* Create one directory per sync point */
431                 snprintf(name, sizeof(name), "%d", i);
432                 kobj = kobject_create_and_add(name, sp->kobj);
433                 if (!kobj) {
434                         err = -EIO;
435                         goto fail;
436                 }
437
438                 min->id = i;
439                 min->host = host;
440                 min->attr.attr.name = min_name;
441                 min->attr.attr.mode = S_IRUGO;
442                 min->attr.show = syncpt_min_show;
443 #ifdef CONFIG_DEBUG_LOCK_ALLOC
444                 sysfs_attr_init(&min->attr.attr);
445                 sysfs_attr_init(&max->attr.attr);
446 #endif
447                 if (sysfs_create_file(kobj, &min->attr.attr)) {
448                         err = -EIO;
449                         goto fail;
450                 }
451
452                 max->id = i;
453                 max->host = host;
454                 max->attr.attr.name = max_name;
455                 max->attr.attr.mode = S_IRUGO;
456                 max->attr.show = syncpt_max_show;
457                 if (sysfs_create_file(kobj, &max->attr.attr)) {
458                         err = -EIO;
459                         goto fail;
460                 }
461         }
462
463         return err;
464
465 fail:
466         nvhost_syncpt_deinit(sp);
467         return err;
468 }
469
470 void nvhost_syncpt_deinit(struct nvhost_syncpt *sp)
471 {
472         kobject_put(sp->kobj);
473
474         kfree(sp->min_val);
475         sp->min_val = NULL;
476
477         kfree(sp->max_val);
478         sp->max_val = NULL;
479
480         kfree(sp->base_val);
481         sp->base_val = NULL;
482
483         kfree(sp->lock_counts);
484         sp->lock_counts = 0;
485
486         kfree(sp->syncpt_attrs);
487         sp->syncpt_attrs = NULL;
488 }
489
490 int nvhost_syncpt_client_managed(struct nvhost_syncpt *sp, u32 id)
491 {
492         return BIT(id) & syncpt_to_dev(sp)->info.client_managed;
493 }
494
495 int nvhost_syncpt_nb_pts(struct nvhost_syncpt *sp)
496 {
497         return syncpt_to_dev(sp)->info.nb_pts;
498 }
499
500 int nvhost_syncpt_nb_bases(struct nvhost_syncpt *sp)
501 {
502         return syncpt_to_dev(sp)->info.nb_bases;
503 }
504
505 int nvhost_syncpt_nb_mlocks(struct nvhost_syncpt *sp)
506 {
507         return syncpt_to_dev(sp)->info.nb_mlocks;
508 }
509
510 /* public sync point API */
511 u32 nvhost_syncpt_incr_max_ext(struct platform_device *dev, u32 id, u32 incrs)
512 {
513         struct platform_device *pdev;
514         struct nvhost_syncpt *sp;
515
516         BUG_ON(!dev->dev.parent);
517
518         /* get the parent */
519         pdev = to_platform_device(dev->dev.parent);
520         sp = &(nvhost_get_host(pdev)->syncpt);
521
522         return nvhost_syncpt_incr_max(sp, id, incrs);
523 }
524
525 void nvhost_syncpt_cpu_incr_ext(struct platform_device *dev, u32 id)
526 {
527         struct platform_device *pdev;
528         struct nvhost_syncpt *sp;
529
530         BUG_ON(!dev->dev.parent);
531
532         /* get the parent */
533         pdev = to_platform_device(dev->dev.parent);
534         sp = &(nvhost_get_host(pdev)->syncpt);
535
536         nvhost_syncpt_cpu_incr(sp, id);
537 }
538
539 u32 nvhost_syncpt_read_ext(struct platform_device *dev, u32 id)
540 {
541         struct platform_device *pdev;
542         struct nvhost_syncpt *sp;
543
544         BUG_ON(!dev->dev.parent);
545
546         /* get the parent */
547         pdev = to_platform_device(dev->dev.parent);
548         sp = &(nvhost_get_host(pdev)->syncpt);
549
550         return nvhost_syncpt_read(sp, id);
551 }
552
553 int nvhost_syncpt_wait_timeout_ext(struct platform_device *dev, u32 id,
554         u32 thresh, u32 timeout, u32 *value)
555 {
556         struct platform_device *pdev;
557         struct nvhost_syncpt *sp;
558
559         BUG_ON(!dev->dev.parent);
560
561         /* get the parent */
562         pdev = to_platform_device(dev->dev.parent);
563         sp = &(nvhost_get_host(pdev)->syncpt);
564
565         return nvhost_syncpt_wait_timeout(sp, id, thresh, timeout, value);
566 }