aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h3
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c1
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c125
3 files changed, 129 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1646d036db09..d1d68f0b55e8 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1576,6 +1576,9 @@ int i915_gem_init_stolen(struct drm_device *dev);
1576int i915_gem_stolen_setup_compression(struct drm_device *dev, int size); 1576int i915_gem_stolen_setup_compression(struct drm_device *dev, int size);
1577void i915_gem_stolen_cleanup_compression(struct drm_device *dev); 1577void i915_gem_stolen_cleanup_compression(struct drm_device *dev);
1578void i915_gem_cleanup_stolen(struct drm_device *dev); 1578void i915_gem_cleanup_stolen(struct drm_device *dev);
1579struct drm_i915_gem_object *
1580i915_gem_object_create_stolen(struct drm_device *dev, u32 size);
1581void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj);
1579 1582
1580/* i915_gem_tiling.c */ 1583/* i915_gem_tiling.c */
1581void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); 1584void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 5c8df572cd17..3de62b0127a5 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3772,6 +3772,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
3772 obj->pages_pin_count = 0; 3772 obj->pages_pin_count = 0;
3773 i915_gem_object_put_pages(obj); 3773 i915_gem_object_put_pages(obj);
3774 i915_gem_object_free_mmap_offset(obj); 3774 i915_gem_object_free_mmap_offset(obj);
3775 i915_gem_object_release_stolen(obj);
3775 3776
3776 BUG_ON(obj->pages); 3777 BUG_ON(obj->pages);
3777 3778
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 10ca473d85f2..7299d632663c 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -192,3 +192,128 @@ int i915_gem_init_stolen(struct drm_device *dev)
192 192
193 return 0; 193 return 0;
194} 194}
195
196static struct sg_table *
197i915_pages_create_for_stolen(struct drm_device *dev,
198 u32 offset, u32 size)
199{
200 struct drm_i915_private *dev_priv = dev->dev_private;
201 struct sg_table *st;
202 struct scatterlist *sg;
203
204 DRM_DEBUG_DRIVER("offset=0x%x, size=%d\n", offset, size);
205 BUG_ON(offset > dev_priv->mm.gtt->stolen_size - size);
206
207 /* We hide that we have no struct page backing our stolen object
208 * by wrapping the contiguous physical allocation with a fake
209 * dma mapping in a single scatterlist.
210 */
211
212 st = kmalloc(sizeof(*st), GFP_KERNEL);
213 if (st == NULL)
214 return NULL;
215
216 if (sg_alloc_table(st, 1, GFP_KERNEL)) {
217 kfree(st);
218 return NULL;
219 }
220
221 sg = st->sgl;
222 sg->offset = offset;
223 sg->length = size;
224
225 sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset;
226 sg_dma_len(sg) = size;
227
228 return st;
229}
230
231static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj)
232{
233 BUG();
234 return -EINVAL;
235}
236
237static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj)
238{
239 /* Should only be called during free */
240 sg_free_table(obj->pages);
241 kfree(obj->pages);
242}
243
244static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = {
245 .get_pages = i915_gem_object_get_pages_stolen,
246 .put_pages = i915_gem_object_put_pages_stolen,
247};
248
249static struct drm_i915_gem_object *
250_i915_gem_object_create_stolen(struct drm_device *dev,
251 struct drm_mm_node *stolen)
252{
253 struct drm_i915_gem_object *obj;
254
255 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
256 if (obj == NULL)
257 return NULL;
258
259 if (drm_gem_private_object_init(dev, &obj->base, stolen->size))
260 goto cleanup;
261
262 i915_gem_object_init(obj, &i915_gem_object_stolen_ops);
263
264 obj->pages = i915_pages_create_for_stolen(dev,
265 stolen->start, stolen->size);
266 if (obj->pages == NULL)
267 goto cleanup;
268
269 obj->has_dma_mapping = true;
270 obj->pages_pin_count = 1;
271 obj->stolen = stolen;
272
273 obj->base.write_domain = I915_GEM_DOMAIN_GTT;
274 obj->base.read_domains = I915_GEM_DOMAIN_GTT;
275 obj->cache_level = I915_CACHE_NONE;
276
277 return obj;
278
279cleanup:
280 kfree(obj);
281 return NULL;
282}
283
284struct drm_i915_gem_object *
285i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
286{
287 struct drm_i915_private *dev_priv = dev->dev_private;
288 struct drm_i915_gem_object *obj;
289 struct drm_mm_node *stolen;
290
291 if (dev_priv->mm.stolen_base == 0)
292 return NULL;
293
294 DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
295 if (size == 0)
296 return NULL;
297
298 stolen = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
299 if (stolen)
300 stolen = drm_mm_get_block(stolen, size, 4096);
301 if (stolen == NULL)
302 return NULL;
303
304 obj = _i915_gem_object_create_stolen(dev, stolen);
305 if (obj)
306 return obj;
307
308 drm_mm_put_block(stolen);
309 return NULL;
310}
311
312void
313i915_gem_object_release_stolen(struct drm_i915_gem_object *obj)
314{
315 if (obj->stolen) {
316 drm_mm_put_block(obj->stolen);
317 obj->stolen = NULL;
318 }
319}