c7b0c82b3e45d313af68526fa4c940025667124f
[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-2012, 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_init(struct nvhost_channel *ch,
36                 struct nvhost_master *dev, int index)
37 {
38         int err;
39         struct nvhost_device *ndev;
40         struct resource *r = NULL;
41         void __iomem *regs = NULL;
42         struct resource *reg_mem = NULL;
43
44         /* Link nvhost_device to nvhost_channel */
45         err = host_channel_op(dev).init(ch, dev, index);
46         if (err < 0) {
47                 dev_err(&dev->dev->dev, "failed to init channel %d\n",
48                                 index);
49                 return err;
50         }
51         ndev = ch->dev;
52         ndev->channel = ch;
53
54         /* Map IO memory related to nvhost_device */
55         if (ndev->moduleid != NVHOST_MODULE_NONE) {
56                 /* First one is host1x - skip that */
57                 r = platform_get_resource(dev->pdev,
58                                 IORESOURCE_MEM, ndev->moduleid + 1);
59                 if (!r)
60                         goto fail;
61
62                 reg_mem = request_mem_region(r->start,
63                                 resource_size(r), ndev->name);
64                 if (!reg_mem)
65                         goto fail;
66
67                 regs = ioremap(r->start, resource_size(r));
68                 if (!regs)
69                         goto fail;
70
71                 ndev->reg_mem = reg_mem;
72                 ndev->aperture = regs;
73         }
74         return 0;
75
76 fail:
77         if (reg_mem)
78                 release_mem_region(r->start, resource_size(r));
79         if (regs)
80                 iounmap(regs);
81         dev_err(&ndev->dev, "failed to get register memory\n");
82         return -ENXIO;
83
84 }
85
86 int nvhost_channel_submit(struct nvhost_job *job)
87 {
88         /* Low priority submits wait until sync queue is empty. Ignores result
89          * from nvhost_cdma_flush, as we submit either when push buffer is
90          * empty or when we reach the timeout. */
91         if (job->priority < NVHOST_PRIORITY_MEDIUM)
92                 (void)nvhost_cdma_flush(&job->ch->cdma,
93                                 NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
94
95         return channel_op(job->ch).submit(job);
96 }
97
98 struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
99 {
100         int err = 0;
101         mutex_lock(&ch->reflock);
102         if (ch->refcount == 0) {
103                 if (ch->dev->init)
104                         ch->dev->init(ch->dev);
105                 err = nvhost_cdma_init(&ch->cdma);
106         } else if (ch->dev->exclusive) {
107                 err = -EBUSY;
108         }
109         if (!err)
110                 ch->refcount++;
111
112         mutex_unlock(&ch->reflock);
113
114         /* Keep alive modules that needs to be when a channel is open */
115         if (!err && ch->dev->keepalive)
116                 nvhost_module_busy(ch->dev);
117
118         return err ? NULL : ch;
119 }
120
121 void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
122 {
123         BUG_ON(!channel_cdma_op(ch).stop);
124
125         if (ctx) {
126                 mutex_lock(&ch->submitlock);
127                 if (ch->cur_ctx == ctx)
128                         ch->cur_ctx = NULL;
129                 mutex_unlock(&ch->submitlock);
130         }
131
132         /* Allow keep-alive'd module to be turned off */
133         if (ch->dev->keepalive)
134                 nvhost_module_idle(ch->dev);
135
136         mutex_lock(&ch->reflock);
137         if (ch->refcount == 1) {
138                 channel_cdma_op(ch).stop(&ch->cdma);
139                 nvhost_cdma_deinit(&ch->cdma);
140                 nvhost_module_suspend(ch->dev, false);
141         }
142         ch->refcount--;
143         mutex_unlock(&ch->reflock);
144 }
145
146 int nvhost_channel_suspend(struct nvhost_channel *ch)
147 {
148         int ret = 0;
149
150         mutex_lock(&ch->reflock);
151         BUG_ON(!channel_cdma_op(ch).stop);
152
153         if (ch->refcount) {
154                 ret = nvhost_module_suspend(ch->dev, false);
155                 if (!ret)
156                         channel_cdma_op(ch).stop(&ch->cdma);
157         }
158         mutex_unlock(&ch->reflock);
159
160         return ret;
161 }