diff options
author | Thierry Reding <treding@nvidia.com> | 2013-10-10 05:00:33 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2013-10-31 04:55:45 -0400 |
commit | c40f0f1afcb1dcce7f9fd978fbbc8d8d68cf5e84 (patch) | |
tree | e038523b47f8e4980e121fa7c337018ee90b910c | |
parent | 497c56a5817f1610ca189e1dc546934c7ce8eb7d (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.c | 129 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gr2d.c | 132 |
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 | ||
112 | static struct host1x_bo * | ||
113 | host1x_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 | |||
130 | int 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 | |||
233 | fail_submit: | ||
234 | host1x_job_unpin(job); | ||
235 | fail: | ||
236 | host1x_job_put(job); | ||
237 | return err; | ||
238 | } | ||
239 | |||
240 | |||
112 | #ifdef CONFIG_DRM_TEGRA_STAGING | 241 | #ifdef CONFIG_DRM_TEGRA_STAGING |
113 | static struct tegra_drm_context *tegra_drm_get_context(__u64 context) | 242 | static 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 | ||
60 | int tegra_drm_submit(struct tegra_drm_context *context, | ||
61 | struct drm_tegra_submit *args, struct drm_device *drm, | ||
62 | struct drm_file *file); | ||
63 | |||
59 | struct tegra_drm_client { | 64 | struct 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 | ||
94 | static 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 | |||
113 | static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset) | 94 | static 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 | ||
138 | static 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 | |||
241 | fail_submit: | ||
242 | host1x_job_unpin(job); | ||
243 | fail: | ||
244 | host1x_job_put(job); | ||
245 | return err; | ||
246 | } | ||
247 | |||
248 | static const struct tegra_drm_client_ops gr2d_ops = { | 119 | static 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 | ||
254 | static const struct of_device_id gr2d_match[] = { | 126 | static const struct of_device_id gr2d_match[] = { |