aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_gem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c60
1 files changed, 37 insertions, 23 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 9ac73dd1b422..dc2e6fdb6ca3 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -171,6 +171,37 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
171 return 0; 171 return 0;
172} 172}
173 173
174/*
175 * Try to write quickly with an atomic kmap. Return true on success.
176 *
177 * If this fails (which includes a partial write), we'll redo the whole
178 * thing with the slow version.
179 *
180 * This is a workaround for the low performance of iounmap (approximate
181 * 10% cpu cost on normal 3D workloads). kmap_atomic on HIGHMEM kernels
182 * happens to let us map card memory without taking IPIs. When the vmap
183 * rework lands we should be able to dump this hack.
184 */
185static inline int fast_user_write(unsigned long pfn, char __user *user_data,
186 int l, int o)
187{
188#ifdef CONFIG_HIGHMEM
189 unsigned long unwritten;
190 char *vaddr_atomic;
191
192 vaddr_atomic = kmap_atomic_pfn(pfn, KM_USER0);
193#if WATCH_PWRITE
194 DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n",
195 i, o, l, pfn, vaddr_atomic);
196#endif
197 unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + o, user_data, l);
198 kunmap_atomic(vaddr_atomic, KM_USER0);
199 return !unwritten;
200#else
201 return 0;
202#endif
203}
204
174static int 205static int
175i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj, 206i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
176 struct drm_i915_gem_pwrite *args, 207 struct drm_i915_gem_pwrite *args,
@@ -180,12 +211,7 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
180 ssize_t remain; 211 ssize_t remain;
181 loff_t offset; 212 loff_t offset;
182 char __user *user_data; 213 char __user *user_data;
183 char __iomem *vaddr;
184 char *vaddr_atomic;
185 int i, o, l;
186 int ret = 0; 214 int ret = 0;
187 unsigned long pfn;
188 unsigned long unwritten;
189 215
190 user_data = (char __user *) (uintptr_t) args->data_ptr; 216 user_data = (char __user *) (uintptr_t) args->data_ptr;
191 remain = args->size; 217 remain = args->size;
@@ -209,6 +235,9 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
209 obj_priv->dirty = 1; 235 obj_priv->dirty = 1;
210 236
211 while (remain > 0) { 237 while (remain > 0) {
238 unsigned long pfn;
239 int i, o, l;
240
212 /* Operation in this page 241 /* Operation in this page
213 * 242 *
214 * i = page number 243 * i = page number
@@ -223,25 +252,10 @@ i915_gem_gtt_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
223 252
224 pfn = (dev->agp->base >> PAGE_SHIFT) + i; 253 pfn = (dev->agp->base >> PAGE_SHIFT) + i;
225 254
226#ifdef CONFIG_HIGHMEM 255 if (!fast_user_write(pfn, user_data, l, o)) {
227 /* This is a workaround for the low performance of iounmap 256 unsigned long unwritten;
228 * (approximate 10% cpu cost on normal 3D workloads). 257 char __iomem *vaddr;
229 * kmap_atomic on HIGHMEM kernels happens to let us map card
230 * memory without taking IPIs. When the vmap rework lands
231 * we should be able to dump this hack.
232 */
233 vaddr_atomic = kmap_atomic_pfn(pfn, KM_USER0);
234#if WATCH_PWRITE
235 DRM_INFO("pwrite i %d o %d l %d pfn %ld vaddr %p\n",
236 i, o, l, pfn, vaddr_atomic);
237#endif
238 unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + o,
239 user_data, l);
240 kunmap_atomic(vaddr_atomic, KM_USER0);
241 258
242 if (unwritten)
243#endif /* CONFIG_HIGHMEM */
244 {
245 vaddr = ioremap_wc(pfn << PAGE_SHIFT, PAGE_SIZE); 259 vaddr = ioremap_wc(pfn << PAGE_SHIFT, PAGE_SIZE);
246#if WATCH_PWRITE 260#if WATCH_PWRITE
247 DRM_INFO("pwrite slow i %d o %d l %d " 261 DRM_INFO("pwrite slow i %d o %d l %d "