aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Widawsky <ben@bwidawsk.net>2012-06-04 17:42:43 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-06-14 11:36:16 -0400
commit40521054fd46f94e0368cead312d56e9e442aaab (patch)
tree14c220ee426bccd22124b9dd0f5688cde5362a7f
parent254f965c39e3918544395f4ebac8c589d890bae6 (diff)
drm/i915: context basic create & destroy
Invent an abstraction for a hw context which is passed around through the core functions. The main bit a hw context holds is the buffer object which backs the context. The rest of the members are just helper functions. Specifically the ring member, which could likely go away if we decide to never implement whatever other hw context support exists. Of note here is the introduction of the 64k alignment constraint for the BO. If contexts become heavily used, we should consider tweaking this down to 4k. Until the contexts are merged and tested a bit though, I think 64k is a nice start (based on docs). Since we don't yet switch contexts, there is really not much complexity here. Creation/destruction works pretty much as one would expect. An idr is used to generate the context id numbers which are unique per file descriptor. v2: add DRM_DEBUG_DRIVERS to distinguish ENOMEM failures (ben) convert a BUG_ON to WARN_ON, default destruction is still fatal (ben) Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h11
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c142
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h2
3 files changed, 153 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8d02951b988b..250eeae7c262 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -308,6 +308,16 @@ struct i915_hw_ppgtt {
308 dma_addr_t scratch_page_dma_addr; 308 dma_addr_t scratch_page_dma_addr;
309}; 309};
310 310
311
312/* This must match up with the value previously used for execbuf2.rsvd1. */
313#define DEFAULT_CONTEXT_ID 0
314struct i915_hw_context {
315 int id;
316 struct drm_i915_file_private *file_priv;
317 struct intel_ring_buffer *ring;
318 struct drm_i915_gem_object *obj;
319};
320
311enum no_fbc_reason { 321enum no_fbc_reason {
312 FBC_NO_OUTPUT, /* no outputs enabled to compress */ 322 FBC_NO_OUTPUT, /* no outputs enabled to compress */
313 FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */ 323 FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
@@ -1032,6 +1042,7 @@ struct drm_i915_file_private {
1032 struct spinlock lock; 1042 struct spinlock lock;
1033 struct list_head request_list; 1043 struct list_head request_list;
1034 } mm; 1044 } mm;
1045 struct idr context_idr;
1035}; 1046};
1036 1047
1037#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info) 1048#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info)
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index e39808e349f1..2aca00235ce3 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -89,6 +89,15 @@
89#include "i915_drm.h" 89#include "i915_drm.h"
90#include "i915_drv.h" 90#include "i915_drv.h"
91 91
92/* This is a HW constraint. The value below is the largest known requirement
93 * I've seen in a spec to date, and that was a workaround for a non-shipping
94 * part. It should be safe to decrease this, but it's more future proof as is.
95 */
96#define CONTEXT_ALIGN (64<<10)
97
98static struct i915_hw_context *
99i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
100
92static int get_context_size(struct drm_device *dev) 101static int get_context_size(struct drm_device *dev)
93{ 102{
94 struct drm_i915_private *dev_priv = dev->dev_private; 103 struct drm_i915_private *dev_priv = dev->dev_private;
@@ -111,6 +120,76 @@ static int get_context_size(struct drm_device *dev)
111 return ret; 120 return ret;
112} 121}
113 122
123static void do_destroy(struct i915_hw_context *ctx)
124{
125 struct drm_device *dev = ctx->obj->base.dev;
126 struct drm_i915_private *dev_priv = dev->dev_private;
127
128 if (ctx->file_priv)
129 idr_remove(&ctx->file_priv->context_idr, ctx->id);
130 else
131 BUG_ON(ctx != dev_priv->ring[RCS].default_context);
132
133 drm_gem_object_unreference(&ctx->obj->base);
134 kfree(ctx);
135}
136
137static int
138create_hw_context(struct drm_device *dev,
139 struct drm_i915_file_private *file_priv,
140 struct i915_hw_context **ctx_out)
141{
142 struct drm_i915_private *dev_priv = dev->dev_private;
143 int ret, id;
144
145 *ctx_out = kzalloc(sizeof(struct drm_i915_file_private), GFP_KERNEL);
146 if (*ctx_out == NULL)
147 return -ENOMEM;
148
149 (*ctx_out)->obj = i915_gem_alloc_object(dev,
150 dev_priv->hw_context_size);
151 if ((*ctx_out)->obj == NULL) {
152 kfree(*ctx_out);
153 DRM_DEBUG_DRIVER("Context object allocated failed\n");
154 return -ENOMEM;
155 }
156
157 /* The ring associated with the context object is handled by the normal
158 * object tracking code. We give an initial ring value simple to pass an
159 * assertion in the context switch code.
160 */
161 (*ctx_out)->ring = &dev_priv->ring[RCS];
162
163 /* Default context will never have a file_priv */
164 if (file_priv == NULL)
165 return 0;
166
167 (*ctx_out)->file_priv = file_priv;
168
169again:
170 if (idr_pre_get(&file_priv->context_idr, GFP_KERNEL) == 0) {
171 ret = -ENOMEM;
172 DRM_DEBUG_DRIVER("idr allocation failed\n");
173 goto err_out;
174 }
175
176 ret = idr_get_new_above(&file_priv->context_idr, *ctx_out,
177 DEFAULT_CONTEXT_ID + 1, &id);
178 if (ret == 0)
179 (*ctx_out)->id = id;
180
181 if (ret == -EAGAIN)
182 goto again;
183 else if (ret)
184 goto err_out;
185
186 return 0;
187
188err_out:
189 do_destroy(*ctx_out);
190 return ret;
191}
192
114/** 193/**
115 * The default context needs to exist per ring that uses contexts. It stores the 194 * The default context needs to exist per ring that uses contexts. It stores the
116 * context state of the GPU for applications that don't utilize HW contexts, as 195 * context state of the GPU for applications that don't utilize HW contexts, as
@@ -118,7 +197,30 @@ static int get_context_size(struct drm_device *dev)
118 */ 197 */
119static int create_default_context(struct drm_i915_private *dev_priv) 198static int create_default_context(struct drm_i915_private *dev_priv)
120{ 199{
121 return 0; 200 struct i915_hw_context *ctx;
201 int ret;
202
203 BUG_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
204
205 ret = create_hw_context(dev_priv->dev, NULL,
206 &dev_priv->ring[RCS].default_context);
207 if (ret)
208 return ret;
209
210 /* We may need to do things with the shrinker which require us to
211 * immediately switch back to the default context. This can cause a
212 * problem as pinning the default context also requires GTT space which
213 * may not be available. To avoid this we always pin the
214 * default context.
215 */
216 ctx = dev_priv->ring[RCS].default_context;
217 ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false);
218 if (ret) {
219 do_destroy(ctx);
220 return ret;
221 }
222
223 return ret;
122} 224}
123 225
124void i915_gem_context_init(struct drm_device *dev) 226void i915_gem_context_init(struct drm_device *dev)
@@ -130,7 +232,8 @@ void i915_gem_context_init(struct drm_device *dev)
130 return; 232 return;
131 233
132 /* If called from reset, or thaw... we've been here already */ 234 /* If called from reset, or thaw... we've been here already */
133 if (dev_priv->hw_contexts_disabled) 235 if (dev_priv->hw_contexts_disabled ||
236 dev_priv->ring[RCS].default_context)
134 return; 237 return;
135 238
136 ctx_size = get_context_size(dev); 239 ctx_size = get_context_size(dev);
@@ -156,20 +259,55 @@ void i915_gem_context_fini(struct drm_device *dev)
156 259
157 if (dev_priv->hw_contexts_disabled) 260 if (dev_priv->hw_contexts_disabled)
158 return; 261 return;
262
263 i915_gem_object_unpin(dev_priv->ring[RCS].default_context->obj);
264
265 do_destroy(dev_priv->ring[RCS].default_context);
159} 266}
160 267
161void i915_gem_context_open(struct drm_device *dev, struct drm_file *file) 268void i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
162{ 269{
163 struct drm_i915_private *dev_priv = dev->dev_private; 270 struct drm_i915_private *dev_priv = dev->dev_private;
271 struct drm_i915_file_private *file_priv = file->driver_priv;
164 272
165 if (dev_priv->hw_contexts_disabled) 273 if (dev_priv->hw_contexts_disabled)
166 return; 274 return;
275
276 idr_init(&file_priv->context_idr);
277}
278
279static int context_idr_cleanup(int id, void *p, void *data)
280{
281 struct drm_file *file = (struct drm_file *)data;
282 struct drm_i915_file_private *file_priv = file->driver_priv;
283 struct i915_hw_context *ctx;
284
285 BUG_ON(id == DEFAULT_CONTEXT_ID);
286 ctx = i915_gem_context_get(file_priv, id);
287 if (WARN_ON(ctx == NULL))
288 return -ENXIO;
289
290 do_destroy(ctx);
291
292 return 0;
167} 293}
168 294
169void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) 295void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
170{ 296{
171 struct drm_i915_private *dev_priv = dev->dev_private; 297 struct drm_i915_private *dev_priv = dev->dev_private;
298 struct drm_i915_file_private *file_priv = file->driver_priv;
172 299
173 if (dev_priv->hw_contexts_disabled) 300 if (dev_priv->hw_contexts_disabled)
174 return; 301 return;
302
303 mutex_lock(&dev->struct_mutex);
304 idr_for_each(&file_priv->context_idr, context_idr_cleanup, file);
305 idr_destroy(&file_priv->context_idr);
306 mutex_unlock(&dev->struct_mutex);
307}
308
309static __used struct i915_hw_context *
310i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)
311{
312 return (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);
175} 313}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 55d3da26bae7..bb19becb1163 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -116,6 +116,8 @@ struct intel_ring_buffer {
116 116
117 wait_queue_head_t irq_queue; 117 wait_queue_head_t irq_queue;
118 118
119 struct i915_hw_context *default_context;
120
119 void *private; 121 void *private;
120}; 122};
121 123