diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_stolen.c | 125 |
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); | |||
1576 | int i915_gem_stolen_setup_compression(struct drm_device *dev, int size); | 1576 | int i915_gem_stolen_setup_compression(struct drm_device *dev, int size); |
1577 | void i915_gem_stolen_cleanup_compression(struct drm_device *dev); | 1577 | void i915_gem_stolen_cleanup_compression(struct drm_device *dev); |
1578 | void i915_gem_cleanup_stolen(struct drm_device *dev); | 1578 | void i915_gem_cleanup_stolen(struct drm_device *dev); |
1579 | struct drm_i915_gem_object * | ||
1580 | i915_gem_object_create_stolen(struct drm_device *dev, u32 size); | ||
1581 | void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj); | ||
1579 | 1582 | ||
1580 | /* i915_gem_tiling.c */ | 1583 | /* i915_gem_tiling.c */ |
1581 | void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); | 1584 | void 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 | |||
196 | static struct sg_table * | ||
197 | i915_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 | |||
231 | static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj) | ||
232 | { | ||
233 | BUG(); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | |||
237 | static 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 | |||
244 | static 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 | |||
249 | static 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 | |||
279 | cleanup: | ||
280 | kfree(obj); | ||
281 | return NULL; | ||
282 | } | ||
283 | |||
284 | struct drm_i915_gem_object * | ||
285 | i915_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 | |||
312 | void | ||
313 | i915_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 | } | ||