aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_gem.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@linux.ie>2008-12-30 05:31:46 -0500
committerDave Airlie <airlied@linux.ie>2009-01-16 03:45:06 -0500
commit71acb5eb8d95b371f4cdd88a47f3c83c870d1c8f (patch)
tree36c370582e69cd61f2f088c31808fc02c6c86f1a /drivers/gpu/drm/i915/i915_gem.c
parente285f3cd2c376d2336f9a383241a98266363c7d4 (diff)
drm/i915: add support for physical memory objects
This is an initial patch to do support for objects which needs physical contiguous main ram, cursors and overlay registers on older chipsets. These objects are bound on cursor bin, like pinning, and we copy the data to/from the backing store object into the real one on attach/detach. notes: possible over the top in attach/detach operations. no overlay support yet. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c189
1 files changed, 187 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 1384d6686555..96316fd47233 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -55,6 +55,9 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
55static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj); 55static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
56static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); 56static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
57static int i915_gem_evict_something(struct drm_device *dev); 57static int i915_gem_evict_something(struct drm_device *dev);
58static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
59 struct drm_i915_gem_pwrite *args,
60 struct drm_file *file_priv);
58 61
59int i915_gem_do_init(struct drm_device *dev, unsigned long start, 62int i915_gem_do_init(struct drm_device *dev, unsigned long start,
60 unsigned long end) 63 unsigned long end)
@@ -386,8 +389,10 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
386 * pread/pwrite currently are reading and writing from the CPU 389 * pread/pwrite currently are reading and writing from the CPU
387 * perspective, requiring manual detiling by the client. 390 * perspective, requiring manual detiling by the client.
388 */ 391 */
389 if (obj_priv->tiling_mode == I915_TILING_NONE && 392 if (obj_priv->phys_obj)
390 dev->gtt_total != 0) 393 ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
394 else if (obj_priv->tiling_mode == I915_TILING_NONE &&
395 dev->gtt_total != 0)
391 ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv); 396 ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
392 else 397 else
393 ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv); 398 ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv);
@@ -2858,6 +2863,9 @@ void i915_gem_free_object(struct drm_gem_object *obj)
2858 while (obj_priv->pin_count > 0) 2863 while (obj_priv->pin_count > 0)
2859 i915_gem_object_unpin(obj); 2864 i915_gem_object_unpin(obj);
2860 2865
2866 if (obj_priv->phys_obj)
2867 i915_gem_detach_phys_object(dev, obj);
2868
2861 i915_gem_object_unbind(obj); 2869 i915_gem_object_unbind(obj);
2862 2870
2863 list = &obj->map_list; 2871 list = &obj->map_list;
@@ -3293,3 +3301,180 @@ i915_gem_load(struct drm_device *dev)
3293 3301
3294 i915_gem_detect_bit_6_swizzle(dev); 3302 i915_gem_detect_bit_6_swizzle(dev);
3295} 3303}
3304
3305/*
3306 * Create a physically contiguous memory object for this object
3307 * e.g. for cursor + overlay regs
3308 */
3309int i915_gem_init_phys_object(struct drm_device *dev,
3310 int id, int size)
3311{
3312 drm_i915_private_t *dev_priv = dev->dev_private;
3313 struct drm_i915_gem_phys_object *phys_obj;
3314 int ret;
3315
3316 if (dev_priv->mm.phys_objs[id - 1] || !size)
3317 return 0;
3318
3319 phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
3320 if (!phys_obj)
3321 return -ENOMEM;
3322
3323 phys_obj->id = id;
3324
3325 phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff);
3326 if (!phys_obj->handle) {
3327 ret = -ENOMEM;
3328 goto kfree_obj;
3329 }
3330#ifdef CONFIG_X86
3331 set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
3332#endif
3333
3334 dev_priv->mm.phys_objs[id - 1] = phys_obj;
3335
3336 return 0;
3337kfree_obj:
3338 drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
3339 return ret;
3340}
3341
3342void i915_gem_free_phys_object(struct drm_device *dev, int id)
3343{
3344 drm_i915_private_t *dev_priv = dev->dev_private;
3345 struct drm_i915_gem_phys_object *phys_obj;
3346
3347 if (!dev_priv->mm.phys_objs[id - 1])
3348 return;
3349
3350 phys_obj = dev_priv->mm.phys_objs[id - 1];
3351 if (phys_obj->cur_obj) {
3352 i915_gem_detach_phys_object(dev, phys_obj->cur_obj);
3353 }
3354
3355#ifdef CONFIG_X86
3356 set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
3357#endif
3358 drm_pci_free(dev, phys_obj->handle);
3359 kfree(phys_obj);
3360 dev_priv->mm.phys_objs[id - 1] = NULL;
3361}
3362
3363void i915_gem_free_all_phys_object(struct drm_device *dev)
3364{
3365 int i;
3366
3367 for (i = 0; i < I915_MAX_PHYS_OBJECT; i++)
3368 i915_gem_free_phys_object(dev, i);
3369}
3370
3371void i915_gem_detach_phys_object(struct drm_device *dev,
3372 struct drm_gem_object *obj)
3373{
3374 struct drm_i915_gem_object *obj_priv;
3375 int i;
3376 int ret;
3377 int page_count;
3378
3379 obj_priv = obj->driver_private;
3380 if (!obj_priv->phys_obj)
3381 return;
3382
3383 ret = i915_gem_object_get_page_list(obj);
3384 if (ret)
3385 goto out;
3386
3387 page_count = obj->size / PAGE_SIZE;
3388
3389 for (i = 0; i < page_count; i++) {
3390 char *dst = kmap_atomic(obj_priv->page_list[i], KM_USER0);
3391 char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
3392
3393 memcpy(dst, src, PAGE_SIZE);
3394 kunmap_atomic(dst, KM_USER0);
3395 }
3396 drm_clflush_pages(obj_priv->page_list, page_count);
3397 drm_agp_chipset_flush(dev);
3398out:
3399 obj_priv->phys_obj->cur_obj = NULL;
3400 obj_priv->phys_obj = NULL;
3401}
3402
3403int
3404i915_gem_attach_phys_object(struct drm_device *dev,
3405 struct drm_gem_object *obj, int id)
3406{
3407 drm_i915_private_t *dev_priv = dev->dev_private;
3408 struct drm_i915_gem_object *obj_priv;
3409 int ret = 0;
3410 int page_count;
3411 int i;
3412
3413 if (id > I915_MAX_PHYS_OBJECT)
3414 return -EINVAL;
3415
3416 obj_priv = obj->driver_private;
3417
3418 if (obj_priv->phys_obj) {
3419 if (obj_priv->phys_obj->id == id)
3420 return 0;
3421 i915_gem_detach_phys_object(dev, obj);
3422 }
3423
3424
3425 /* create a new object */
3426 if (!dev_priv->mm.phys_objs[id - 1]) {
3427 ret = i915_gem_init_phys_object(dev, id,
3428 obj->size);
3429 if (ret) {
3430 DRM_ERROR("failed to init phys object %d size: %d\n", id, obj->size);
3431 goto out;
3432 }
3433 }
3434
3435 /* bind to the object */
3436 obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
3437 obj_priv->phys_obj->cur_obj = obj;
3438
3439 ret = i915_gem_object_get_page_list(obj);
3440 if (ret) {
3441 DRM_ERROR("failed to get page list\n");
3442 goto out;
3443 }
3444
3445 page_count = obj->size / PAGE_SIZE;
3446
3447 for (i = 0; i < page_count; i++) {
3448 char *src = kmap_atomic(obj_priv->page_list[i], KM_USER0);
3449 char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
3450
3451 memcpy(dst, src, PAGE_SIZE);
3452 kunmap_atomic(src, KM_USER0);
3453 }
3454
3455 return 0;
3456out:
3457 return ret;
3458}
3459
3460static int
3461i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
3462 struct drm_i915_gem_pwrite *args,
3463 struct drm_file *file_priv)
3464{
3465 struct drm_i915_gem_object *obj_priv = obj->driver_private;
3466 void *obj_addr;
3467 int ret;
3468 char __user *user_data;
3469
3470 user_data = (char __user *) (uintptr_t) args->data_ptr;
3471 obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
3472
3473 DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size);
3474 ret = copy_from_user(obj_addr, user_data, args->size);
3475 if (ret)
3476 return -EFAULT;
3477
3478 drm_agp_chipset_flush(dev);
3479 return 0;
3480}