85256016ad707935bb3542c58640c90677a5b3cb
[linux-2.6.git] / drivers / video / tegra / host / nvhost_channel.c
1 /*
2  * drivers/video/tegra/host/nvhost_channel.c
3  *
4  * Tegra Graphics Host Channel
5  *
6  * Copyright (c) 2010-2011, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  */
22
23 #include "nvhost_channel.h"
24 #include "dev.h"
25 #include "nvhost_hwctx.h"
26 #include "nvhost_job.h"
27 #include <trace/events/nvhost.h>
28 #include <linux/nvhost_ioctl.h>
29 #include <linux/slab.h>
30
31 #include <linux/platform_device.h>
32
33 #define NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT 50
34
35 int nvhost_channel_submit(struct nvhost_job *job)
36 {
37         /* Low priority submits wait until sync queue is empty. Ignores result
38          * from nvhost_cdma_flush, as we submit either when push buffer is
39          * empty or when we reach the timeout. */
40         if (job->priority < NVHOST_PRIORITY_MEDIUM)
41                 (void)nvhost_cdma_flush(&job->ch->cdma,
42                                 NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
43
44         return channel_op(job->ch).submit(job);
45 }
46
47 struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
48 {
49         int err = 0;
50         mutex_lock(&ch->reflock);
51         if (ch->refcount == 0) {
52                 err = nvhost_module_init(&ch->mod, ch->desc->name,
53                                         &ch->desc->module,
54                                         &ch->dev->mod,
55                                         &ch->dev->pdev->dev);
56                 if (!err) {
57                         err = nvhost_cdma_init(&ch->cdma);
58                         if (err)
59                                 nvhost_module_deinit(&ch->dev->pdev->dev,
60                                                 &ch->mod);
61                 }
62         } else if (ch->desc->exclusive) {
63                 err = -EBUSY;
64         }
65         if (!err)
66                 ch->refcount++;
67
68         mutex_unlock(&ch->reflock);
69
70         /* Keep alive modules that needs to be when a channel is open */
71         if (!err && ch->desc->keepalive)
72                 nvhost_module_busy(&ch->mod);
73
74         return err ? NULL : ch;
75 }
76
77 void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
78 {
79         BUG_ON(!channel_cdma_op(ch).stop);
80
81         if (ctx) {
82                 mutex_lock(&ch->submitlock);
83                 if (ch->cur_ctx == ctx)
84                         ch->cur_ctx = NULL;
85                 mutex_unlock(&ch->submitlock);
86         }
87
88         /* Allow keep-alive'd module to be turned off */
89         if (ch->desc->keepalive)
90                 nvhost_module_idle(&ch->mod);
91
92         mutex_lock(&ch->reflock);
93         if (ch->refcount == 1) {
94                 channel_cdma_op(ch).stop(&ch->cdma);
95                 nvhost_cdma_deinit(&ch->cdma);
96                 nvhost_module_deinit(&ch->dev->pdev->dev, &ch->mod);
97         }
98         ch->refcount--;
99         mutex_unlock(&ch->reflock);
100 }
101
102 int nvhost_channel_suspend(struct nvhost_channel *ch)
103 {
104         int ret = 0;
105
106         mutex_lock(&ch->reflock);
107         BUG_ON(!channel_cdma_op(ch).stop);
108
109         if (ch->refcount) {
110                 ret = nvhost_module_suspend(&ch->mod, false);
111                 if (!ret)
112                         channel_cdma_op(ch).stop(&ch->cdma);
113         }
114         mutex_unlock(&ch->reflock);
115
116         return ret;
117 }