drm/i915: Make a single set-to-gtt-domain path.

This fixes failure to flush caches in the relocation update path, and
failure to wait in the set_domain ioctl, each of which could lead to incorrect
rendering.

Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Eric Anholt and committed by
Dave Airlie
2ef7eeaa b670d815

+96 -19
+96 -19
drivers/gpu/drm/i915/i915_gem.c
··· 48 48 struct drm_file *file_priv, 49 49 uint32_t read_domains, 50 50 uint32_t write_domain); 51 + static int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, 52 + int write); 51 53 static int i915_gem_object_get_page_list(struct drm_gem_object *obj); 52 54 static void i915_gem_object_free_page_list(struct drm_gem_object *obj); 53 55 static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); ··· 262 260 mutex_unlock(&dev->struct_mutex); 263 261 return ret; 264 262 } 265 - ret = i915_gem_set_domain(obj, file_priv, 266 - I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); 263 + ret = i915_gem_object_set_to_gtt_domain(obj, 1); 267 264 if (ret) 268 265 goto fail; 269 266 ··· 398 397 } 399 398 400 399 /** 401 - * Called when user space prepares to use an object 400 + * Called when user space prepares to use an object with the CPU, either 401 + * through the mmap ioctl's mapping or a GTT mapping. 402 402 */ 403 403 int 404 404 i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, ··· 407 405 { 408 406 struct drm_i915_gem_set_domain *args = data; 409 407 struct drm_gem_object *obj; 408 + uint32_t read_domains = args->read_domains; 409 + uint32_t write_domain = args->write_domain; 410 410 int ret; 411 411 412 412 if (!(dev->driver->driver_features & DRIVER_GEM)) 413 413 return -ENODEV; 414 + 415 + /* Only handle setting domains to types used by the CPU. */ 416 + if (write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) 417 + return -EINVAL; 418 + 419 + if (read_domains & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) 420 + return -EINVAL; 421 + 422 + /* Having something in the write domain implies it's in the read 423 + * domain, and only that read domain. Enforce that in the request. 424 + */ 425 + if (write_domain != 0 && read_domains != write_domain) 426 + return -EINVAL; 414 427 415 428 obj = drm_gem_object_lookup(dev, file_priv, args->handle); 416 429 if (obj == NULL) ··· 434 417 mutex_lock(&dev->struct_mutex); 435 418 #if WATCH_BUF 436 419 DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n", 437 - obj, obj->size, args->read_domains, args->write_domain); 420 + obj, obj->size, read_domains, write_domain); 438 421 #endif 439 - ret = i915_gem_set_domain(obj, file_priv, 440 - args->read_domains, args->write_domain); 422 + if (read_domains & I915_GEM_DOMAIN_GTT) { 423 + ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); 424 + } else { 425 + ret = i915_gem_set_domain(obj, file_priv, 426 + read_domains, write_domain); 427 + } 428 + 441 429 drm_gem_object_unreference(obj); 442 430 mutex_unlock(&dev->struct_mutex); 443 431 return ret; ··· 1259 1237 drm_clflush_pages(obj_priv->page_list, obj->size / PAGE_SIZE); 1260 1238 } 1261 1239 1240 + /** 1241 + * Moves a single object to the GTT read, and possibly write domain. 1242 + * 1243 + * This function returns when the move is complete, including waiting on 1244 + * flushes to occur. 1245 + */ 1246 + static int 1247 + i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) 1248 + { 1249 + struct drm_device *dev = obj->dev; 1250 + struct drm_i915_gem_object *obj_priv = obj->driver_private; 1251 + uint32_t flush_domains; 1252 + 1253 + /* Figure out what GPU domains we need to flush or invalidate for 1254 + * moving to GTT. 1255 + */ 1256 + flush_domains = obj->write_domain & I915_GEM_GPU_DOMAINS; 1257 + 1258 + /* Queue the GPU write cache flushing we need. */ 1259 + if (flush_domains != 0) { 1260 + uint32_t seqno; 1261 + 1262 + obj->write_domain &= ~I915_GEM_GPU_DOMAINS; 1263 + i915_gem_flush(dev, 0, flush_domains); 1264 + seqno = i915_add_request(dev, flush_domains); 1265 + i915_gem_object_move_to_active(obj, seqno); 1266 + } 1267 + 1268 + /* Wait on any GPU rendering and flushing to occur. */ 1269 + if (obj_priv->active) { 1270 + int ret; 1271 + 1272 + ret = i915_wait_request(dev, obj_priv->last_rendering_seqno); 1273 + if (ret != 0) 1274 + return ret; 1275 + } 1276 + 1277 + /* If we're writing through the GTT domain, then CPU and GPU caches 1278 + * will need to be invalidated at next use. 1279 + */ 1280 + if (write) 1281 + obj->read_domains &= ~(I915_GEM_GPU_DOMAINS | 1282 + I915_GEM_DOMAIN_CPU); 1283 + 1284 + /* Flush the CPU domain if it's dirty. */ 1285 + if (obj->write_domain & I915_GEM_DOMAIN_CPU) { 1286 + i915_gem_clflush_object(obj); 1287 + drm_agp_chipset_flush(dev); 1288 + 1289 + obj->write_domain &= ~I915_GEM_DOMAIN_CPU; 1290 + } 1291 + 1292 + /* It should now be out of any other write domains, and we can update 1293 + * the domain values for our changes. 1294 + */ 1295 + BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0); 1296 + obj->read_domains |= I915_GEM_DOMAIN_GTT; 1297 + if (write) 1298 + obj->write_domain = I915_GEM_DOMAIN_GTT; 1299 + 1300 + return 0; 1301 + } 1302 + 1262 1303 /* 1263 1304 * Set the next domain for the specified object. This 1264 1305 * may not actually perform the necessary flushing/invaliding though, ··· 1719 1634 continue; 1720 1635 } 1721 1636 1722 - /* Now that we're going to actually write some data in, 1723 - * make sure that any rendering using this buffer's contents 1724 - * is completed. 1725 - */ 1726 - i915_gem_object_wait_rendering(obj); 1727 - 1728 - /* As we're writing through the gtt, flush 1729 - * any CPU writes before we write the relocations 1730 - */ 1731 - if (obj->write_domain & I915_GEM_DOMAIN_CPU) { 1732 - i915_gem_clflush_object(obj); 1733 - drm_agp_chipset_flush(dev); 1734 - obj->write_domain = 0; 1637 + ret = i915_gem_object_set_to_gtt_domain(obj, 1); 1638 + if (ret != 0) { 1639 + drm_gem_object_unreference(target_obj); 1640 + i915_gem_object_unpin(obj); 1641 + return -EINVAL; 1735 1642 } 1736 1643 1737 1644 /* Map the page containing the relocation we're going to