aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2013-10-10 05:00:33 -0400
committerThierry Reding <treding@nvidia.com>2013-10-31 04:55:45 -0400
commitc40f0f1afcb1dcce7f9fd978fbbc8d8d68cf5e84 (patch)
treee038523b47f8e4980e121fa7c337018ee90b910c
parent497c56a5817f1610ca189e1dc546934c7ce8eb7d (diff)
drm/tegra: Introduce tegra_drm_submit()
Command stream submissions are the same across all devices that expose a channel to userspace, so move the code into a generic function. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/tegra/drm.c129
-rw-r--r--drivers/gpu/drm/tegra/drm.h5
-rw-r--r--drivers/gpu/drm/tegra/gr2d.c132
3 files changed, 136 insertions, 130 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 2d8f925899de..6f42f1692f29 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -109,6 +109,135 @@ static void tegra_drm_lastclose(struct drm_device *drm)
109 tegra_fbdev_restore_mode(tegra->fbdev); 109 tegra_fbdev_restore_mode(tegra->fbdev);
110} 110}
111 111
112static struct host1x_bo *
113host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle)
114{
115 struct drm_gem_object *gem;
116 struct tegra_bo *bo;
117
118 gem = drm_gem_object_lookup(drm, file, handle);
119 if (!gem)
120 return NULL;
121
122 mutex_lock(&drm->struct_mutex);
123 drm_gem_object_unreference(gem);
124 mutex_unlock(&drm->struct_mutex);
125
126 bo = to_tegra_bo(gem);
127 return &bo->base;
128}
129
130int tegra_drm_submit(struct tegra_drm_context *context,
131 struct drm_tegra_submit *args, struct drm_device *drm,
132 struct drm_file *file)
133{
134 unsigned int num_cmdbufs = args->num_cmdbufs;
135 unsigned int num_relocs = args->num_relocs;
136 unsigned int num_waitchks = args->num_waitchks;
137 struct drm_tegra_cmdbuf __user *cmdbufs =
138 (void * __user)(uintptr_t)args->cmdbufs;
139 struct drm_tegra_reloc __user *relocs =
140 (void * __user)(uintptr_t)args->relocs;
141 struct drm_tegra_waitchk __user *waitchks =
142 (void * __user)(uintptr_t)args->waitchks;
143 struct drm_tegra_syncpt syncpt;
144 struct host1x_job *job;
145 int err;
146
147 /* We don't yet support other than one syncpt_incr struct per submit */
148 if (args->num_syncpts != 1)
149 return -EINVAL;
150
151 job = host1x_job_alloc(context->channel, args->num_cmdbufs,
152 args->num_relocs, args->num_waitchks);
153 if (!job)
154 return -ENOMEM;
155
156 job->num_relocs = args->num_relocs;
157 job->num_waitchk = args->num_waitchks;
158 job->client = (u32)args->context;
159 job->class = context->client->base.class;
160 job->serialize = true;
161
162 while (num_cmdbufs) {
163 struct drm_tegra_cmdbuf cmdbuf;
164 struct host1x_bo *bo;
165
166 err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf));
167 if (err)
168 goto fail;
169
170 bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
171 if (!bo) {
172 err = -ENOENT;
173 goto fail;
174 }
175
176 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
177 num_cmdbufs--;
178 cmdbufs++;
179 }
180
181 err = copy_from_user(job->relocarray, relocs,
182 sizeof(*relocs) * num_relocs);
183 if (err)
184 goto fail;
185
186 while (num_relocs--) {
187 struct host1x_reloc *reloc = &job->relocarray[num_relocs];
188 struct host1x_bo *cmdbuf, *target;
189
190 cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf);
191 target = host1x_bo_lookup(drm, file, (u32)reloc->target);
192
193 reloc->cmdbuf = cmdbuf;
194 reloc->target = target;
195
196 if (!reloc->target || !reloc->cmdbuf) {
197 err = -ENOENT;
198 goto fail;
199 }
200 }
201
202 err = copy_from_user(job->waitchk, waitchks,
203 sizeof(*waitchks) * num_waitchks);
204 if (err)
205 goto fail;
206
207 err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts,
208 sizeof(syncpt));
209 if (err)
210 goto fail;
211
212 job->is_addr_reg = context->client->ops->is_addr_reg;
213 job->syncpt_incrs = syncpt.incrs;
214 job->syncpt_id = syncpt.id;
215 job->timeout = 10000;
216
217 if (args->timeout && args->timeout < 10000)
218 job->timeout = args->timeout;
219
220 err = host1x_job_pin(job, context->client->base.dev);
221 if (err)
222 goto fail;
223
224 err = host1x_job_submit(job);
225 if (err)
226 goto fail_submit;
227
228 args->fence = job->syncpt_end;
229
230 host1x_job_put(job);
231 return 0;
232
233fail_submit:
234 host1x_job_unpin(job);
235fail:
236 host1x_job_put(job);
237 return err;
238}
239
240
112#ifdef CONFIG_DRM_TEGRA_STAGING 241#ifdef CONFIG_DRM_TEGRA_STAGING
113static struct tegra_drm_context *tegra_drm_get_context(__u64 context) 242static struct tegra_drm_context *tegra_drm_get_context(__u64 context)
114{ 243{
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index dc4b994fe613..e3cd3ed438d5 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -51,11 +51,16 @@ struct tegra_drm_client_ops {
51 int (*open_channel)(struct tegra_drm_client *client, 51 int (*open_channel)(struct tegra_drm_client *client,
52 struct tegra_drm_context *context); 52 struct tegra_drm_context *context);
53 void (*close_channel)(struct tegra_drm_context *context); 53 void (*close_channel)(struct tegra_drm_context *context);
54 int (*is_addr_reg)(struct device *dev, u32 class, u32 offset);
54 int (*submit)(struct tegra_drm_context *context, 55 int (*submit)(struct tegra_drm_context *context,
55 struct drm_tegra_submit *args, struct drm_device *drm, 56 struct drm_tegra_submit *args, struct drm_device *drm,
56 struct drm_file *file); 57 struct drm_file *file);
57}; 58};
58 59
60int tegra_drm_submit(struct tegra_drm_context *context,
61 struct drm_tegra_submit *args, struct drm_device *drm,
62 struct drm_file *file);
63
59struct tegra_drm_client { 64struct tegra_drm_client {
60 struct host1x_client base; 65 struct host1x_client base;
61 struct list_head list; 66 struct list_head list;
diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c
index bbeedc24d004..73b79bad613e 100644
--- a/drivers/gpu/drm/tegra/gr2d.c
+++ b/drivers/gpu/drm/tegra/gr2d.c
@@ -91,25 +91,6 @@ static void gr2d_close_channel(struct tegra_drm_context *context)
91 host1x_channel_put(context->channel); 91 host1x_channel_put(context->channel);
92} 92}
93 93
94static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm,
95 struct drm_file *file,
96 u32 handle)
97{
98 struct drm_gem_object *gem;
99 struct tegra_bo *bo;
100
101 gem = drm_gem_object_lookup(drm, file, handle);
102 if (!gem)
103 return NULL;
104
105 mutex_lock(&drm->struct_mutex);
106 drm_gem_object_unreference(gem);
107 mutex_unlock(&drm->struct_mutex);
108
109 bo = to_tegra_bo(gem);
110 return &bo->base;
111}
112
113static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset) 94static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset)
114{ 95{
115 struct gr2d *gr2d = dev_get_drvdata(dev); 96 struct gr2d *gr2d = dev_get_drvdata(dev);
@@ -135,120 +116,11 @@ static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset)
135 return 0; 116 return 0;
136} 117}
137 118
138static int gr2d_submit(struct tegra_drm_context *context,
139 struct drm_tegra_submit *args, struct drm_device *drm,
140 struct drm_file *file)
141{
142 unsigned int num_cmdbufs = args->num_cmdbufs;
143 unsigned int num_relocs = args->num_relocs;
144 unsigned int num_waitchks = args->num_waitchks;
145 struct drm_tegra_cmdbuf __user *cmdbufs =
146 (void * __user)(uintptr_t)args->cmdbufs;
147 struct drm_tegra_reloc __user *relocs =
148 (void * __user)(uintptr_t)args->relocs;
149 struct drm_tegra_waitchk __user *waitchks =
150 (void * __user)(uintptr_t)args->waitchks;
151 struct drm_tegra_syncpt syncpt;
152 struct host1x_job *job;
153 int err;
154
155 /* We don't yet support other than one syncpt_incr struct per submit */
156 if (args->num_syncpts != 1)
157 return -EINVAL;
158
159 job = host1x_job_alloc(context->channel, args->num_cmdbufs,
160 args->num_relocs, args->num_waitchks);
161 if (!job)
162 return -ENOMEM;
163
164 job->num_relocs = args->num_relocs;
165 job->num_waitchk = args->num_waitchks;
166 job->client = (u32)args->context;
167 job->class = context->client->base.class;
168 job->serialize = true;
169
170 while (num_cmdbufs) {
171 struct drm_tegra_cmdbuf cmdbuf;
172 struct host1x_bo *bo;
173
174 err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf));
175 if (err)
176 goto fail;
177
178 bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
179 if (!bo) {
180 err = -ENOENT;
181 goto fail;
182 }
183
184 host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
185 num_cmdbufs--;
186 cmdbufs++;
187 }
188
189 err = copy_from_user(job->relocarray, relocs,
190 sizeof(*relocs) * num_relocs);
191 if (err)
192 goto fail;
193
194 while (num_relocs--) {
195 struct host1x_reloc *reloc = &job->relocarray[num_relocs];
196 struct host1x_bo *cmdbuf, *target;
197
198 cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf);
199 target = host1x_bo_lookup(drm, file, (u32)reloc->target);
200
201 reloc->cmdbuf = cmdbuf;
202 reloc->target = target;
203
204 if (!reloc->target || !reloc->cmdbuf) {
205 err = -ENOENT;
206 goto fail;
207 }
208 }
209
210 err = copy_from_user(job->waitchk, waitchks,
211 sizeof(*waitchks) * num_waitchks);
212 if (err)
213 goto fail;
214
215 err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts,
216 sizeof(syncpt));
217 if (err)
218 goto fail;
219
220 job->syncpt_id = syncpt.id;
221 job->syncpt_incrs = syncpt.incrs;
222 job->timeout = 10000;
223 job->is_addr_reg = gr2d_is_addr_reg;
224
225 if (args->timeout && args->timeout < 10000)
226 job->timeout = args->timeout;
227
228 err = host1x_job_pin(job, context->client->base.dev);
229 if (err)
230 goto fail;
231
232 err = host1x_job_submit(job);
233 if (err)
234 goto fail_submit;
235
236 args->fence = job->syncpt_end;
237
238 host1x_job_put(job);
239 return 0;
240
241fail_submit:
242 host1x_job_unpin(job);
243fail:
244 host1x_job_put(job);
245 return err;
246}
247
248static const struct tegra_drm_client_ops gr2d_ops = { 119static const struct tegra_drm_client_ops gr2d_ops = {
249 .open_channel = gr2d_open_channel, 120 .open_channel = gr2d_open_channel,
250 .close_channel = gr2d_close_channel, 121 .close_channel = gr2d_close_channel,
251 .submit = gr2d_submit, 122 .is_addr_reg = gr2d_is_addr_reg,
123 .submit = tegra_drm_submit,
252}; 124};
253 125
254static const struct of_device_id gr2d_match[] = { 126static const struct of_device_id gr2d_match[] = {