X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fi915%2Fi915_gem.c;h=17ae330ff269b10610d12a237ed9412f8e5e5856;hb=5579a782ad7ffa162b1060993e4a298dd50e7a33;hp=94b9bdce0c75c447b59b743b16fa77644e94b96e;hpb=50aa253d820ad4577e2231202f2c8fd89f9dc4e6;p=linux-2.6-omap-h63xx.git diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 94b9bdce0c7..17ae330ff26 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -50,6 +50,9 @@ static int i915_gem_object_get_page_list(struct drm_gem_object *obj); static void i915_gem_object_free_page_list(struct drm_gem_object *obj); static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); +static void +i915_gem_cleanup_ringbuffer(struct drm_device *dev); + int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -168,6 +171,37 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, return 0; } +/* + * Try to write quickly with an atomic kmap. Return true on success. + * + * If this fails (which includes a partial write), we'll redo the whole + * thing with the slow version. + * + * This is a workaround for the low performance of iounmap (approximate + * 10% cpu cost on normal 3D workloads). kmap_atomic on HIGHMEM kernels + * happens to let us map card memory without taking IPIs. When the vmap + * rework lands we should be able to dump this hack. + */ +static inline int fast_user_write(unsigned long pfn, char __user *user_data, + int l, int o) +{ +#ifdef CONFIG_HIGHMEM + unsigned long unwritten; + char *vaddr_atomic; + + vaddr_atomic = kmap_atomic_pfn(pfn, KM_USER0); +#if WATCH_PWRITE + DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n", + i, o, l, pfn, vaddr_atomic); +#endif + unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + o, user_data, l); + kunmap_atomic(vaddr_atomic, KM_USER0); + return !unwritten; +#else + return 0; +#endif +} + static int i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -177,12 +211,7 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, ssize_t remain; loff_t offset; char __user *user_data; - char __iomem *vaddr; - char *vaddr_atomic; - int i, o, l; int ret = 0; - unsigned long pfn; - unsigned long unwritten; user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; @@ -206,6 +235,9 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, obj_priv->dirty = 1; while (remain > 0) { + unsigned long pfn; + int i, o, l; + /* Operation in this page * * i = page number @@ -220,25 +252,10 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, pfn = (dev->agp->base >> PAGE_SHIFT) + i; -#ifdef CONFIG_HIGHMEM - /* This is a workaround for the low performance of iounmap - * (approximate 10% cpu cost on normal 3D workloads). - * kmap_atomic on HIGHMEM kernels happens to let us map card - * memory without taking IPIs. When the vmap rework lands - * we should be able to dump this hack. - */ - vaddr_atomic = kmap_atomic_pfn(pfn, KM_USER0); -#if WATCH_PWRITE - DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n", - i, o, l, pfn, vaddr_atomic); -#endif - unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + o, - user_data, l); - kunmap_atomic(vaddr_atomic, KM_USER0); + if (!fast_user_write(pfn, user_data, l, o)) { + unsigned long unwritten; + char __iomem *vaddr; - if (unwritten) -#endif /* CONFIG_HIGHMEM */ - { vaddr = ioremap_wc(pfn << PAGE_SHIFT, PAGE_SIZE); #if WATCH_PWRITE DRM_INFO("pwrite slow i %d o %d l %d " @@ -582,7 +599,7 @@ i915_add_request(struct drm_device *dev, uint32_t flush_domains) was_empty = list_empty(&dev_priv->mm.request_list); list_add_tail(&request->list, &dev_priv->mm.request_list); - if (was_empty) + if (was_empty && !dev_priv->mm.suspended) schedule_delayed_work(&dev_priv->mm.retire_work, HZ); return seqno; } @@ -731,7 +748,8 @@ i915_gem_retire_work_handler(struct work_struct *work) mutex_lock(&dev->struct_mutex); i915_gem_retire_requests(dev); - if (!list_empty(&dev_priv->mm.request_list)) + if (!dev_priv->mm.suspended && + !list_empty(&dev_priv->mm.request_list)) schedule_delayed_work(&dev_priv->mm.retire_work, HZ); mutex_unlock(&dev->struct_mutex); } @@ -1159,7 +1177,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) obj_priv->agp_mem = drm_agp_bind_pages(dev, obj_priv->page_list, page_count, - obj_priv->gtt_offset); + obj_priv->gtt_offset, + obj_priv->agp_type); if (obj_priv->agp_mem == NULL) { i915_gem_object_free_page_list(obj); drm_mm_put_block(obj_priv->gtt_space); @@ -2142,6 +2161,8 @@ int i915_gem_init_object(struct drm_gem_object *obj) obj->write_domain = I915_GEM_DOMAIN_CPU; obj->read_domains = I915_GEM_DOMAIN_CPU; + obj_priv->agp_type = AGP_USER_MEMORY; + obj->driver_private = obj_priv; obj_priv->obj = obj; INIT_LIST_HEAD(&obj_priv->list); @@ -2224,14 +2245,24 @@ i915_gem_idle(struct drm_device *dev) uint32_t seqno, cur_seqno, last_seqno; int stuck, ret; - if (dev_priv->mm.suspended) + mutex_lock(&dev->struct_mutex); + + if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) { + mutex_unlock(&dev->struct_mutex); return 0; + } /* Hack! Don't let anybody do execbuf while we don't control the chip. * We need to replace this with a semaphore, or something. */ dev_priv->mm.suspended = 1; + /* Cancel the retire work handler, wait for it to finish if running + */ + mutex_unlock(&dev->struct_mutex); + cancel_delayed_work_sync(&dev_priv->mm.retire_work); + mutex_lock(&dev->struct_mutex); + i915_kernel_lost_context(dev); /* Flush the GPU along with all non-CPU write domains @@ -2281,13 +2312,19 @@ i915_gem_idle(struct drm_device *dev) /* Move all buffers out of the GTT. */ ret = i915_gem_evict_from_list(dev, &dev_priv->mm.inactive_list); - if (ret) + if (ret) { + mutex_unlock(&dev->struct_mutex); return ret; + } BUG_ON(!list_empty(&dev_priv->mm.active_list)); BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); BUG_ON(!list_empty(&dev_priv->mm.request_list)); + + i915_gem_cleanup_ringbuffer(dev); + mutex_unlock(&dev->struct_mutex); + return 0; } @@ -2311,6 +2348,7 @@ i915_gem_init_hws(struct drm_device *dev) return -ENOMEM; } obj_priv = obj->driver_private; + obj_priv->agp_type = AGP_USER_CACHED_MEMORY; ret = i915_gem_object_pin(obj, 4096); if (ret != 0) { @@ -2319,25 +2357,18 @@ i915_gem_init_hws(struct drm_device *dev) } dev_priv->status_gfx_addr = obj_priv->gtt_offset; - dev_priv->hws_map.offset = dev->agp->base + obj_priv->gtt_offset; - dev_priv->hws_map.size = 4096; - dev_priv->hws_map.type = 0; - dev_priv->hws_map.flags = 0; - dev_priv->hws_map.mtrr = 0; - /* Ioremapping here is the wrong thing to do. We want cached access. - */ - drm_core_ioremap_wc(&dev_priv->hws_map, dev); - if (dev_priv->hws_map.handle == NULL) { + dev_priv->hw_status_page = kmap(obj_priv->page_list[0]); + if (dev_priv->hw_status_page == NULL) { DRM_ERROR("Failed to map status page.\n"); memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); drm_gem_object_unreference(obj); return -EINVAL; } dev_priv->hws_obj = obj; - dev_priv->hw_status_page = dev_priv->hws_map.handle; memset(dev_priv->hw_status_page, 0, PAGE_SIZE); I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); + I915_READ(HWS_PGA); /* posting read */ DRM_DEBUG("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); return 0; @@ -2456,10 +2487,15 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); if (dev_priv->hws_obj != NULL) { - i915_gem_object_unpin(dev_priv->hws_obj); - drm_gem_object_unreference(dev_priv->hws_obj); + struct drm_gem_object *obj = dev_priv->hws_obj; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + + kunmap(obj_priv->page_list[0]); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); dev_priv->hws_obj = NULL; memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); + dev_priv->hw_status_page = NULL; /* Write high address into HWS_PGA when disabling. */ I915_WRITE(HWS_PGA, 0x1ffff000); @@ -2501,34 +2537,20 @@ i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, { int ret; - mutex_lock(&dev->struct_mutex); ret = i915_gem_idle(dev); - if (ret == 0) - i915_gem_cleanup_ringbuffer(dev); - mutex_unlock(&dev->struct_mutex); - drm_irq_uninstall(dev); - return 0; + return ret; } void i915_gem_lastclose(struct drm_device *dev) { int ret; - drm_i915_private_t *dev_priv = dev->dev_private; - - mutex_lock(&dev->struct_mutex); - if (dev_priv->ring.ring_obj != NULL) { - ret = i915_gem_idle(dev); - if (ret) - DRM_ERROR("failed to idle hardware: %d\n", ret); - - i915_gem_cleanup_ringbuffer(dev); - } - - mutex_unlock(&dev->struct_mutex); + ret = i915_gem_idle(dev); + if (ret) + DRM_ERROR("failed to idle hardware: %d\n", ret); } void @@ -2542,8 +2564,6 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->mm.request_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); - INIT_WORK(&dev_priv->mm.vblank_work, - i915_gem_vblank_work_handler); dev_priv->mm.next_gem_seqno = 1; i915_gem_detect_bit_6_swizzle(dev);