d69883ee51b2698b7204aa9a7d10da90059d42a6
[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 "nvhost_syncpt.h"
25 #include "nvhost_acm.h"
26 #include "dev.h"
27
28 #define MAX_STUCK_CHECK_COUNT 15
29 #define MAX_SYNCPT_LENGTH 5
30 /* Name of sysfs node for min and max value */
31 static const char *min_name = "min";
32 static const char *max_name = "max";
33
34 /**
35  * Resets syncpoint and waitbase values to sw shadows
36  */
37 void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
38 {
39         u32 i;
40         BUG_ON(!(syncpt_op(sp).reset && syncpt_op(sp).reset_wait_base));
41
42         for (i = 0; i < sp->nb_pts; i++)
43                 syncpt_op(sp).reset(sp, i);
44         for (i = 0; i < sp->nb_bases; i++)
45                 syncpt_op(sp).reset_wait_base(sp, i);
46         wmb();
47 }
48
49 /**
50  * Updates sw shadow state for client managed registers
51  */
52 void nvhost_syncpt_save(struct nvhost_syncpt *sp)
53 {
54         u32 i;
55         BUG_ON(!(syncpt_op(sp).update_min && syncpt_op(sp).read_wait_base));
56
57         for (i = 0; i < sp->nb_pts; i++) {
58                 if (client_managed(i))
59                         syncpt_op(sp).update_min(sp, i);
60                 else
61                         BUG_ON(!nvhost_syncpt_min_eq_max(sp, i));
62         }
63
64         for (i = 0; i < sp->nb_bases; i++)
65                 syncpt_op(sp).read_wait_base(sp, i);
66 }
67
68 /**
69  * Updates the last value read from hardware.
70  */
71 u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
72 {
73         BUG_ON(!syncpt_op(sp).update_min);
74
75         return syncpt_op(sp).update_min(sp, id);
76 }
77
78 /**
79  * Get the current syncpoint value
80  */
81 u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
82 {
83         u32 val;
84         BUG_ON(!syncpt_op(sp).update_min);
85         nvhost_module_busy(syncpt_to_dev(sp)->dev);
86         val = syncpt_op(sp).update_min(sp, id);
87         nvhost_module_idle(syncpt_to_dev(sp)->dev);
88         return val;
89 }
90
91 /**
92  * Get the current syncpoint base
93  */
94 u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
95 {
96         u32 val;
97         BUG_ON(!syncpt_op(sp).read_wait_base);
98         nvhost_module_busy(syncpt_to_dev(sp)->dev);
99         syncpt_op(sp).read_wait_base(sp, id);
100         val = sp->base_val[id];
101         nvhost_module_idle(syncpt_to_dev(sp)->dev);
102         return val;
103 }
104
105 /**
106  * Write a cpu syncpoint increment to the hardware, without touching
107  * the cache. Caller is responsible for host being powered.
108  */
109 void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
110 {
111         BUG_ON(!syncpt_op(sp).cpu_incr);
112         syncpt_op(sp).cpu_incr(sp, id);
113 }
114
115 /**
116  * Increment syncpoint value from cpu, updating cache
117  */
118 void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id)
119 {
120         if (client_managed(id))
121                 nvhost_syncpt_incr_max(sp, id, 1);
122         nvhost_module_busy(syncpt_to_dev(sp)->dev);
123         nvhost_syncpt_cpu_incr(sp, id);
124         nvhost_module_idle(syncpt_to_dev(sp)->dev);
125 }
126
127 /**
128  * Main entrypoint for syncpoint value waits.
129  */
130 int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
131                         u32 thresh, u32 timeout, u32 *value)
132 {
133         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
134         void *ref;
135         void *waiter;
136         int err = 0, check_count = 0, low_timeout = 0;
137         u32 val;
138
139         if (value)
140                 *value = 0;
141
142         /* first check cache */
143         if (nvhost_syncpt_is_expired(sp, id, thresh)) {
144                 if (value)
145                         *value = nvhost_syncpt_read_min(sp, id);
146                 return 0;
147         }
148
149         /* keep host alive */
150         nvhost_module_busy(syncpt_to_dev(sp)->dev);
151
152         /* try to read from register */
153         val = syncpt_op(sp).update_min(sp, id);
154         if (nvhost_syncpt_is_expired(sp, id, thresh)) {
155                 if (value)
156                         *value = val;
157                 goto done;
158         }
159
160         if (!timeout) {
161                 err = -EAGAIN;
162                 goto done;
163         }
164
165         /* schedule a wakeup when the syncpoint value is reached */
166         waiter = nvhost_intr_alloc_waiter();
167         if (!waiter) {
168                 err = -ENOMEM;
169                 goto done;
170         }
171
172         err = nvhost_intr_add_action(&(syncpt_to_dev(sp)->intr), id, thresh,
173                                 NVHOST_INTR_ACTION_WAKEUP_INTERRUPTIBLE, &wq,
174                                 waiter,
175                                 &ref);
176         if (err)
177                 goto done;
178
179         err = -EAGAIN;
180         /* Caller-specified timeout may be impractically low */
181         if (timeout < SYNCPT_CHECK_PERIOD)
182                 low_timeout = timeout;
183
184         /* wait for the syncpoint, or timeout, or signal */
185         while (timeout) {
186                 u32 check = min_t(u32, SYNCPT_CHECK_PERIOD, timeout);
187                 int remain = wait_event_interruptible_timeout(wq,
188                                 nvhost_syncpt_is_expired(sp, id, thresh),
189                                 check);
190                 if (remain > 0) {
191                         if (value)
192                                 *value = nvhost_syncpt_read_min(sp, id);
193                         err = 0;
194                         break;
195                 }
196                 if (remain < 0) {
197                         err = remain;
198                         break;
199                 }
200                 if (timeout != NVHOST_NO_TIMEOUT)
201                         timeout -= check;
202                 if (timeout) {
203                         dev_warn(&syncpt_to_dev(sp)->dev->dev,
204                                 "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%d\n",
205                                  current->comm, id, syncpt_op(sp).name(sp, id),
206                                  thresh, timeout);
207                         syncpt_op(sp).debug(sp);
208                         if (check_count > MAX_STUCK_CHECK_COUNT) {
209                                 if (low_timeout) {
210                                         dev_warn(&syncpt_to_dev(sp)->dev->dev,
211                                                 "is timeout %d too low?\n",
212                                                 low_timeout);
213                                 }
214                                 nvhost_debug_dump(syncpt_to_dev(sp));
215                                 BUG();
216                         }
217                         check_count++;
218                 }
219         }
220         nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), ref);
221
222 done:
223         nvhost_module_idle(syncpt_to_dev(sp)->dev);
224         return err;
225 }
226
227 /**
228  * Returns true if syncpoint is expired, false if we may need to wait
229  */
230 bool nvhost_syncpt_is_expired(
231         struct nvhost_syncpt *sp,
232         u32 id,
233         u32 thresh)
234 {
235         u32 current_val;
236         u32 future_val;
237         smp_rmb();
238         current_val = (u32)atomic_read(&sp->min_val[id]);
239         future_val = (u32)atomic_read(&sp->max_val[id]);
240
241         /* Note the use of unsigned arithmetic here (mod 1<<32).
242          *
243          * c = current_val = min_val    = the current value of the syncpoint.
244          * t = thresh                   = the value we are checking
245          * f = future_val  = max_val    = the value c will reach when all
246          *                                outstanding increments have completed.
247          *
248          * Note that c always chases f until it reaches f.
249          *
250          * Dtf = (f - t)
251          * Dtc = (c - t)
252          *
253          *  Consider all cases:
254          *
255          *      A) .....c..t..f.....    Dtf < Dtc       need to wait
256          *      B) .....c.....f..t..    Dtf > Dtc       expired
257          *      C) ..t..c.....f.....    Dtf > Dtc       expired    (Dct very large)
258          *
259          *  Any case where f==c: always expired (for any t).    Dtf == Dcf
260          *  Any case where t==c: always expired (for any f).    Dtf >= Dtc (because Dtc==0)
261          *  Any case where t==f!=c: always wait.                Dtf <  Dtc (because Dtf==0,
262          *                                                      Dtc!=0)
263          *
264          *  Other cases:
265          *
266          *      A) .....t..f..c.....    Dtf < Dtc       need to wait
267          *      A) .....f..c..t.....    Dtf < Dtc       need to wait
268          *      A) .....f..t..c.....    Dtf > Dtc       expired
269          *
270          *   So:
271          *         Dtf >= Dtc implies EXPIRED   (return true)
272          *         Dtf <  Dtc implies WAIT      (return false)
273          *
274          * Note: If t is expired then we *cannot* wait on it. We would wait
275          * forever (hang the system).
276          *
277          * Note: do NOT get clever and remove the -thresh from both sides. It
278          * is NOT the same.
279          *
280          * If future valueis zero, we have a client managed sync point. In that
281          * case we do a direct comparison.
282          */
283         if (!client_managed(id))
284                 return future_val - thresh >= current_val - thresh;
285         else
286                 return (s32)(current_val - thresh) >= 0;
287 }
288
289 void nvhost_syncpt_debug(struct nvhost_syncpt *sp)
290 {
291         syncpt_op(sp).debug(sp);
292 }
293
294 int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
295 {
296         struct nvhost_master *host = syncpt_to_dev(sp);
297         u32 reg;
298
299         nvhost_module_busy(host->dev);
300         reg = syncpt_op(sp).mutex_try_lock(sp, idx);
301         if (reg) {
302                 nvhost_module_idle(host->dev);
303                 return -EBUSY;
304         }
305         atomic_inc(&sp->lock_counts[idx]);
306         return 0;
307 }
308
309 void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx)
310 {
311         syncpt_op(sp).mutex_unlock(sp, idx);
312         nvhost_module_idle(syncpt_to_dev(sp)->dev);
313         atomic_dec(&sp->lock_counts[idx]);
314 }
315
316 /* check for old WAITs to be removed (avoiding a wrap) */
317 int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
318                              struct nvmap_client *nvmap,
319                              u32 waitchk_mask,
320                              struct nvhost_waitchk *wait,
321                              int num_waitchk)
322 {
323         return syncpt_op(sp).wait_check(sp, nvmap,
324                         waitchk_mask, wait, num_waitchk);
325 }
326
327 /* Displays the current value of the sync point via sysfs */
328 static ssize_t syncpt_min_show(struct kobject *kobj,
329                 struct kobj_attribute *attr, char *buf)
330 {
331         struct nvhost_syncpt_attr *syncpt_attr =
332                 container_of(attr, struct nvhost_syncpt_attr, attr);
333
334         return snprintf(buf, PAGE_SIZE, "%d",
335                         nvhost_syncpt_read(&syncpt_attr->host->syncpt,
336                                 syncpt_attr->id));
337 }
338
339 static ssize_t syncpt_max_show(struct kobject *kobj,
340                 struct kobj_attribute *attr, char *buf)
341 {
342         struct nvhost_syncpt_attr *syncpt_attr =
343                 container_of(attr, struct nvhost_syncpt_attr, attr);
344
345         return snprintf(buf, PAGE_SIZE, "%d",
346                         nvhost_syncpt_read_max(&syncpt_attr->host->syncpt,
347                                 syncpt_attr->id));
348 }
349
350 int nvhost_syncpt_init(struct nvhost_device *dev,
351                 struct nvhost_syncpt *sp)
352 {
353         int i;
354         struct nvhost_master *host = syncpt_to_dev(sp);
355         int err = 0;
356
357         /* Allocate structs for min, max and base values */
358         sp->min_val = kzalloc(sizeof(atomic_t) * sp->nb_pts, GFP_KERNEL);
359         sp->max_val = kzalloc(sizeof(atomic_t) * sp->nb_pts, GFP_KERNEL);
360         sp->base_val = kzalloc(sizeof(u32) * sp->nb_bases, GFP_KERNEL);
361         sp->lock_counts = kzalloc(sizeof(atomic_t) * sp->nb_mlocks, GFP_KERNEL);
362
363         if (!(sp->min_val && sp->max_val && sp->base_val && sp->lock_counts)) {
364                 /* frees happen in the deinit */
365                 err = -ENOMEM;
366                 goto fail;
367         }
368
369         sp->kobj = kobject_create_and_add("syncpt", &dev->dev.kobj);
370         if (!sp->kobj) {
371                 err = -EIO;
372                 goto fail;
373         }
374
375         /* Allocate two attributes for each sync point: min and max */
376         sp->syncpt_attrs = kzalloc(sizeof(*sp->syncpt_attrs) * sp->nb_pts * 2,
377                         GFP_KERNEL);
378         if (!sp->syncpt_attrs) {
379                 err = -ENOMEM;
380                 goto fail;
381         }
382
383         /* Fill in the attributes */
384         for (i = 0; i < sp->nb_pts; i++) {
385                 char name[MAX_SYNCPT_LENGTH];
386                 struct kobject *kobj;
387                 struct nvhost_syncpt_attr *min = &sp->syncpt_attrs[i*2];
388                 struct nvhost_syncpt_attr *max = &sp->syncpt_attrs[i*2+1];
389
390                 /* Create one directory per sync point */
391                 snprintf(name, sizeof(name), "%d", i);
392                 kobj = kobject_create_and_add(name, sp->kobj);
393                 if (!kobj) {
394                         err = -EIO;
395                         goto fail;
396                 }
397
398                 min->id = i;
399                 min->host = host;
400                 min->attr.attr.name = min_name;
401                 min->attr.attr.mode = S_IRUGO;
402                 min->attr.show = syncpt_min_show;
403                 if (sysfs_create_file(kobj, &min->attr.attr)) {
404                         err = -EIO;
405                         goto fail;
406                 }
407
408                 max->id = i;
409                 max->host = host;
410                 max->attr.attr.name = max_name;
411                 max->attr.attr.mode = S_IRUGO;
412                 max->attr.show = syncpt_max_show;
413                 if (sysfs_create_file(kobj, &max->attr.attr)) {
414                         err = -EIO;
415                         goto fail;
416                 }
417         }
418
419         return err;
420
421 fail:
422         nvhost_syncpt_deinit(sp);
423         return err;
424 }
425
426 void nvhost_syncpt_deinit(struct nvhost_syncpt *sp)
427 {
428         kobject_put(sp->kobj);
429
430         kfree(sp->min_val);
431         sp->min_val = NULL;
432
433         kfree(sp->max_val);
434         sp->max_val = NULL;
435
436         kfree(sp->base_val);
437         sp->base_val = NULL;
438
439         kfree(sp->lock_counts);
440         sp->lock_counts = 0;
441
442         kfree(sp->syncpt_attrs);
443         sp->syncpt_attrs = NULL;
444 }