diff options
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 379 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 87 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 98 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | 150 |
4 files changed, 620 insertions, 94 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 96dc84dc34d0..7776e6f0aef6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | |||
| @@ -141,37 +141,374 @@ struct ttm_placement vmw_srf_placement = { | |||
| 141 | }; | 141 | }; |
| 142 | 142 | ||
| 143 | struct vmw_ttm_tt { | 143 | struct vmw_ttm_tt { |
| 144 | struct ttm_tt ttm; | 144 | struct ttm_dma_tt dma_ttm; |
| 145 | struct vmw_private *dev_priv; | 145 | struct vmw_private *dev_priv; |
| 146 | int gmr_id; | 146 | int gmr_id; |
| 147 | struct sg_table sgt; | ||
| 148 | struct vmw_sg_table vsgt; | ||
| 149 | uint64_t sg_alloc_size; | ||
| 150 | bool mapped; | ||
| 147 | }; | 151 | }; |
| 148 | 152 | ||
| 153 | /** | ||
| 154 | * Helper functions to advance a struct vmw_piter iterator. | ||
| 155 | * | ||
| 156 | * @viter: Pointer to the iterator. | ||
| 157 | * | ||
| 158 | * These functions return false if past the end of the list, | ||
| 159 | * true otherwise. Functions are selected depending on the current | ||
| 160 | * DMA mapping mode. | ||
| 161 | */ | ||
| 162 | static bool __vmw_piter_non_sg_next(struct vmw_piter *viter) | ||
| 163 | { | ||
| 164 | return ++(viter->i) < viter->num_pages; | ||
| 165 | } | ||
| 166 | |||
| 167 | static bool __vmw_piter_sg_next(struct vmw_piter *viter) | ||
| 168 | { | ||
| 169 | return __sg_page_iter_next(&viter->iter); | ||
| 170 | } | ||
| 171 | |||
| 172 | |||
| 173 | /** | ||
| 174 | * Helper functions to return a pointer to the current page. | ||
| 175 | * | ||
| 176 | * @viter: Pointer to the iterator | ||
| 177 | * | ||
| 178 | * These functions return a pointer to the page currently | ||
| 179 | * pointed to by @viter. Functions are selected depending on the | ||
| 180 | * current mapping mode. | ||
| 181 | */ | ||
| 182 | static struct page *__vmw_piter_non_sg_page(struct vmw_piter *viter) | ||
| 183 | { | ||
| 184 | return viter->pages[viter->i]; | ||
| 185 | } | ||
| 186 | |||
| 187 | static struct page *__vmw_piter_sg_page(struct vmw_piter *viter) | ||
| 188 | { | ||
| 189 | return sg_page_iter_page(&viter->iter); | ||
| 190 | } | ||
| 191 | |||
| 192 | |||
| 193 | /** | ||
| 194 | * Helper functions to return the DMA address of the current page. | ||
| 195 | * | ||
| 196 | * @viter: Pointer to the iterator | ||
| 197 | * | ||
| 198 | * These functions return the DMA address of the page currently | ||
| 199 | * pointed to by @viter. Functions are selected depending on the | ||
| 200 | * current mapping mode. | ||
| 201 | */ | ||
| 202 | static dma_addr_t __vmw_piter_phys_addr(struct vmw_piter *viter) | ||
| 203 | { | ||
| 204 | return page_to_phys(viter->pages[viter->i]); | ||
| 205 | } | ||
| 206 | |||
| 207 | static dma_addr_t __vmw_piter_dma_addr(struct vmw_piter *viter) | ||
| 208 | { | ||
| 209 | return viter->addrs[viter->i]; | ||
| 210 | } | ||
| 211 | |||
| 212 | static dma_addr_t __vmw_piter_sg_addr(struct vmw_piter *viter) | ||
| 213 | { | ||
| 214 | return sg_page_iter_dma_address(&viter->iter); | ||
| 215 | } | ||
| 216 | |||
| 217 | |||
| 218 | /** | ||
| 219 | * vmw_piter_start - Initialize a struct vmw_piter. | ||
| 220 | * | ||
| 221 | * @viter: Pointer to the iterator to initialize | ||
| 222 | * @vsgt: Pointer to a struct vmw_sg_table to initialize from | ||
| 223 | * | ||
| 224 | * Note that we're following the convention of __sg_page_iter_start, so that | ||
| 225 | * the iterator doesn't point to a valid page after initialization; it has | ||
| 226 | * to be advanced one step first. | ||
| 227 | */ | ||
| 228 | void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt, | ||
| 229 | unsigned long p_offset) | ||
| 230 | { | ||
| 231 | viter->i = p_offset - 1; | ||
| 232 | viter->num_pages = vsgt->num_pages; | ||
| 233 | switch (vsgt->mode) { | ||
| 234 | case vmw_dma_phys: | ||
| 235 | viter->next = &__vmw_piter_non_sg_next; | ||
| 236 | viter->dma_address = &__vmw_piter_phys_addr; | ||
| 237 | viter->page = &__vmw_piter_non_sg_page; | ||
| 238 | viter->pages = vsgt->pages; | ||
| 239 | break; | ||
| 240 | case vmw_dma_alloc_coherent: | ||
| 241 | viter->next = &__vmw_piter_non_sg_next; | ||
| 242 | viter->dma_address = &__vmw_piter_dma_addr; | ||
| 243 | viter->page = &__vmw_piter_non_sg_page; | ||
| 244 | viter->addrs = vsgt->addrs; | ||
| 245 | break; | ||
| 246 | case vmw_dma_map_populate: | ||
| 247 | case vmw_dma_map_bind: | ||
| 248 | viter->next = &__vmw_piter_sg_next; | ||
| 249 | viter->dma_address = &__vmw_piter_sg_addr; | ||
| 250 | viter->page = &__vmw_piter_sg_page; | ||
| 251 | __sg_page_iter_start(&viter->iter, vsgt->sgt->sgl, | ||
| 252 | vsgt->sgt->orig_nents, p_offset); | ||
| 253 | break; | ||
| 254 | default: | ||
| 255 | BUG(); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | /** | ||
| 260 | * vmw_ttm_unmap_from_dma - unmap device addresses previsouly mapped for | ||
| 261 | * TTM pages | ||
| 262 | * | ||
| 263 | * @vmw_tt: Pointer to a struct vmw_ttm_backend | ||
| 264 | * | ||
| 265 | * Used to free dma mappings previously mapped by vmw_ttm_map_for_dma. | ||
| 266 | */ | ||
| 267 | static void vmw_ttm_unmap_from_dma(struct vmw_ttm_tt *vmw_tt) | ||
| 268 | { | ||
| 269 | struct device *dev = vmw_tt->dev_priv->dev->dev; | ||
| 270 | |||
| 271 | dma_unmap_sg(dev, vmw_tt->sgt.sgl, vmw_tt->sgt.nents, | ||
| 272 | DMA_BIDIRECTIONAL); | ||
| 273 | vmw_tt->sgt.nents = vmw_tt->sgt.orig_nents; | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * vmw_ttm_map_for_dma - map TTM pages to get device addresses | ||
| 278 | * | ||
| 279 | * @vmw_tt: Pointer to a struct vmw_ttm_backend | ||
| 280 | * | ||
| 281 | * This function is used to get device addresses from the kernel DMA layer. | ||
| 282 | * However, it's violating the DMA API in that when this operation has been | ||
| 283 | * performed, it's illegal for the CPU to write to the pages without first | ||
| 284 | * unmapping the DMA mappings, or calling dma_sync_sg_for_cpu(). It is | ||
| 285 | * therefore only legal to call this function if we know that the function | ||
| 286 | * dma_sync_sg_for_cpu() is a NOP, and dma_sync_sg_for_device() is at most | ||
| 287 | * a CPU write buffer flush. | ||
| 288 | */ | ||
| 289 | static int vmw_ttm_map_for_dma(struct vmw_ttm_tt *vmw_tt) | ||
| 290 | { | ||
| 291 | struct device *dev = vmw_tt->dev_priv->dev->dev; | ||
| 292 | int ret; | ||
| 293 | |||
| 294 | ret = dma_map_sg(dev, vmw_tt->sgt.sgl, vmw_tt->sgt.orig_nents, | ||
| 295 | DMA_BIDIRECTIONAL); | ||
| 296 | if (unlikely(ret == 0)) | ||
| 297 | return -ENOMEM; | ||
| 298 | |||
| 299 | vmw_tt->sgt.nents = ret; | ||
| 300 | |||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | /** | ||
| 305 | * vmw_ttm_map_dma - Make sure TTM pages are visible to the device | ||
| 306 | * | ||
| 307 | * @vmw_tt: Pointer to a struct vmw_ttm_tt | ||
| 308 | * | ||
| 309 | * Select the correct function for and make sure the TTM pages are | ||
| 310 | * visible to the device. Allocate storage for the device mappings. | ||
| 311 | * If a mapping has already been performed, indicated by the storage | ||
| 312 | * pointer being non NULL, the function returns success. | ||
| 313 | */ | ||
| 314 | static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt) | ||
| 315 | { | ||
| 316 | struct vmw_private *dev_priv = vmw_tt->dev_priv; | ||
| 317 | struct ttm_mem_global *glob = vmw_mem_glob(dev_priv); | ||
| 318 | struct vmw_sg_table *vsgt = &vmw_tt->vsgt; | ||
| 319 | struct vmw_piter iter; | ||
| 320 | dma_addr_t old; | ||
| 321 | int ret = 0; | ||
| 322 | static size_t sgl_size; | ||
| 323 | static size_t sgt_size; | ||
| 324 | |||
| 325 | if (vmw_tt->mapped) | ||
| 326 | return 0; | ||
| 327 | |||
| 328 | vsgt->mode = dev_priv->map_mode; | ||
| 329 | vsgt->pages = vmw_tt->dma_ttm.ttm.pages; | ||
| 330 | vsgt->num_pages = vmw_tt->dma_ttm.ttm.num_pages; | ||
| 331 | vsgt->addrs = vmw_tt->dma_ttm.dma_address; | ||
| 332 | vsgt->sgt = &vmw_tt->sgt; | ||
| 333 | |||
| 334 | switch (dev_priv->map_mode) { | ||
| 335 | case vmw_dma_map_bind: | ||
| 336 | case vmw_dma_map_populate: | ||
| 337 | if (unlikely(!sgl_size)) { | ||
| 338 | sgl_size = ttm_round_pot(sizeof(struct scatterlist)); | ||
| 339 | sgt_size = ttm_round_pot(sizeof(struct sg_table)); | ||
| 340 | } | ||
| 341 | vmw_tt->sg_alloc_size = sgt_size + sgl_size * vsgt->num_pages; | ||
| 342 | ret = ttm_mem_global_alloc(glob, vmw_tt->sg_alloc_size, false, | ||
| 343 | true); | ||
| 344 | if (unlikely(ret != 0)) | ||
| 345 | return ret; | ||
| 346 | |||
| 347 | ret = sg_alloc_table_from_pages(&vmw_tt->sgt, vsgt->pages, | ||
| 348 | vsgt->num_pages, 0, | ||
| 349 | (unsigned long) | ||
| 350 | vsgt->num_pages << PAGE_SHIFT, | ||
| 351 | GFP_KERNEL); | ||
| 352 | if (unlikely(ret != 0)) | ||
| 353 | goto out_sg_alloc_fail; | ||
| 354 | |||
| 355 | if (vsgt->num_pages > vmw_tt->sgt.nents) { | ||
| 356 | uint64_t over_alloc = | ||
| 357 | sgl_size * (vsgt->num_pages - | ||
| 358 | vmw_tt->sgt.nents); | ||
| 359 | |||
| 360 | ttm_mem_global_free(glob, over_alloc); | ||
| 361 | vmw_tt->sg_alloc_size -= over_alloc; | ||
| 362 | } | ||
| 363 | |||
| 364 | ret = vmw_ttm_map_for_dma(vmw_tt); | ||
| 365 | if (unlikely(ret != 0)) | ||
| 366 | goto out_map_fail; | ||
| 367 | |||
| 368 | break; | ||
| 369 | default: | ||
| 370 | break; | ||
| 371 | } | ||
| 372 | |||
| 373 | old = ~((dma_addr_t) 0); | ||
| 374 | vmw_tt->vsgt.num_regions = 0; | ||
| 375 | for (vmw_piter_start(&iter, vsgt, 0); vmw_piter_next(&iter);) { | ||
| 376 | dma_addr_t cur = vmw_piter_dma_addr(&iter); | ||
| 377 | |||
| 378 | if (cur != old + PAGE_SIZE) | ||
| 379 | vmw_tt->vsgt.num_regions++; | ||
| 380 | old = cur; | ||
| 381 | } | ||
| 382 | |||
| 383 | vmw_tt->mapped = true; | ||
| 384 | return 0; | ||
| 385 | |||
| 386 | out_map_fail: | ||
| 387 | sg_free_table(vmw_tt->vsgt.sgt); | ||
| 388 | vmw_tt->vsgt.sgt = NULL; | ||
| 389 | out_sg_alloc_fail: | ||
| 390 | ttm_mem_global_free(glob, vmw_tt->sg_alloc_size); | ||
| 391 | return ret; | ||
| 392 | } | ||
| 393 | |||
| 394 | /** | ||
| 395 | * vmw_ttm_unmap_dma - Tear down any TTM page device mappings | ||
| 396 | * | ||
| 397 | * @vmw_tt: Pointer to a struct vmw_ttm_tt | ||
| 398 | * | ||
| 399 | * Tear down any previously set up device DMA mappings and free | ||
| 400 | * any storage space allocated for them. If there are no mappings set up, | ||
| 401 | * this function is a NOP. | ||
| 402 | */ | ||
| 403 | static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt) | ||
| 404 | { | ||
| 405 | struct vmw_private *dev_priv = vmw_tt->dev_priv; | ||
| 406 | |||
| 407 | if (!vmw_tt->vsgt.sgt) | ||
| 408 | return; | ||
| 409 | |||
| 410 | switch (dev_priv->map_mode) { | ||
| 411 | case vmw_dma_map_bind: | ||
| 412 | case vmw_dma_map_populate: | ||
| 413 | vmw_ttm_unmap_from_dma(vmw_tt); | ||
| 414 | sg_free_table(vmw_tt->vsgt.sgt); | ||
| 415 | vmw_tt->vsgt.sgt = NULL; | ||
| 416 | ttm_mem_global_free(vmw_mem_glob(dev_priv), | ||
| 417 | vmw_tt->sg_alloc_size); | ||
| 418 | break; | ||
| 419 | default: | ||
| 420 | break; | ||
| 421 | } | ||
| 422 | vmw_tt->mapped = false; | ||
| 423 | } | ||
| 424 | |||
| 149 | static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) | 425 | static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) |
| 150 | { | 426 | { |
| 151 | struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm); | 427 | struct vmw_ttm_tt *vmw_be = |
| 428 | container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm); | ||
| 429 | int ret; | ||
| 430 | |||
| 431 | ret = vmw_ttm_map_dma(vmw_be); | ||
| 432 | if (unlikely(ret != 0)) | ||
| 433 | return ret; | ||
| 152 | 434 | ||
| 153 | vmw_be->gmr_id = bo_mem->start; | 435 | vmw_be->gmr_id = bo_mem->start; |
| 154 | 436 | ||
| 155 | return vmw_gmr_bind(vmw_be->dev_priv, ttm->pages, | 437 | return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt, |
| 156 | ttm->num_pages, vmw_be->gmr_id); | 438 | ttm->num_pages, vmw_be->gmr_id); |
| 157 | } | 439 | } |
| 158 | 440 | ||
| 159 | static int vmw_ttm_unbind(struct ttm_tt *ttm) | 441 | static int vmw_ttm_unbind(struct ttm_tt *ttm) |
| 160 | { | 442 | { |
| 161 | struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm); | 443 | struct vmw_ttm_tt *vmw_be = |
| 444 | container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm); | ||
| 162 | 445 | ||
| 163 | vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id); | 446 | vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id); |
| 447 | |||
| 448 | if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind) | ||
| 449 | vmw_ttm_unmap_dma(vmw_be); | ||
| 450 | |||
| 164 | return 0; | 451 | return 0; |
| 165 | } | 452 | } |
| 166 | 453 | ||
| 167 | static void vmw_ttm_destroy(struct ttm_tt *ttm) | 454 | static void vmw_ttm_destroy(struct ttm_tt *ttm) |
| 168 | { | 455 | { |
| 169 | struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm); | 456 | struct vmw_ttm_tt *vmw_be = |
| 170 | 457 | container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm); | |
| 171 | ttm_tt_fini(ttm); | 458 | |
| 459 | vmw_ttm_unmap_dma(vmw_be); | ||
| 460 | if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent) | ||
| 461 | ttm_dma_tt_fini(&vmw_be->dma_ttm); | ||
| 462 | else | ||
| 463 | ttm_tt_fini(ttm); | ||
| 172 | kfree(vmw_be); | 464 | kfree(vmw_be); |
| 173 | } | 465 | } |
| 174 | 466 | ||
| 467 | static int vmw_ttm_populate(struct ttm_tt *ttm) | ||
| 468 | { | ||
| 469 | struct vmw_ttm_tt *vmw_tt = | ||
| 470 | container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm); | ||
| 471 | struct vmw_private *dev_priv = vmw_tt->dev_priv; | ||
| 472 | struct ttm_mem_global *glob = vmw_mem_glob(dev_priv); | ||
| 473 | int ret; | ||
| 474 | |||
| 475 | if (ttm->state != tt_unpopulated) | ||
| 476 | return 0; | ||
| 477 | |||
| 478 | if (dev_priv->map_mode == vmw_dma_alloc_coherent) { | ||
| 479 | size_t size = | ||
| 480 | ttm_round_pot(ttm->num_pages * sizeof(dma_addr_t)); | ||
| 481 | ret = ttm_mem_global_alloc(glob, size, false, true); | ||
| 482 | if (unlikely(ret != 0)) | ||
| 483 | return ret; | ||
| 484 | |||
| 485 | ret = ttm_dma_populate(&vmw_tt->dma_ttm, dev_priv->dev->dev); | ||
| 486 | if (unlikely(ret != 0)) | ||
| 487 | ttm_mem_global_free(glob, size); | ||
| 488 | } else | ||
| 489 | ret = ttm_pool_populate(ttm); | ||
| 490 | |||
| 491 | return ret; | ||
| 492 | } | ||
| 493 | |||
| 494 | static void vmw_ttm_unpopulate(struct ttm_tt *ttm) | ||
| 495 | { | ||
| 496 | struct vmw_ttm_tt *vmw_tt = container_of(ttm, struct vmw_ttm_tt, | ||
| 497 | dma_ttm.ttm); | ||
| 498 | struct vmw_private *dev_priv = vmw_tt->dev_priv; | ||
| 499 | struct ttm_mem_global *glob = vmw_mem_glob(dev_priv); | ||
| 500 | |||
| 501 | vmw_ttm_unmap_dma(vmw_tt); | ||
| 502 | if (dev_priv->map_mode == vmw_dma_alloc_coherent) { | ||
| 503 | size_t size = | ||
| 504 | ttm_round_pot(ttm->num_pages * sizeof(dma_addr_t)); | ||
| 505 | |||
| 506 | ttm_dma_unpopulate(&vmw_tt->dma_ttm, dev_priv->dev->dev); | ||
| 507 | ttm_mem_global_free(glob, size); | ||
| 508 | } else | ||
| 509 | ttm_pool_unpopulate(ttm); | ||
| 510 | } | ||
| 511 | |||
| 175 | static struct ttm_backend_func vmw_ttm_func = { | 512 | static struct ttm_backend_func vmw_ttm_func = { |
| 176 | .bind = vmw_ttm_bind, | 513 | .bind = vmw_ttm_bind, |
| 177 | .unbind = vmw_ttm_unbind, | 514 | .unbind = vmw_ttm_unbind, |
| @@ -183,20 +520,28 @@ struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev, | |||
| 183 | struct page *dummy_read_page) | 520 | struct page *dummy_read_page) |
| 184 | { | 521 | { |
| 185 | struct vmw_ttm_tt *vmw_be; | 522 | struct vmw_ttm_tt *vmw_be; |
| 523 | int ret; | ||
| 186 | 524 | ||
| 187 | vmw_be = kmalloc(sizeof(*vmw_be), GFP_KERNEL); | 525 | vmw_be = kzalloc(sizeof(*vmw_be), GFP_KERNEL); |
| 188 | if (!vmw_be) | 526 | if (!vmw_be) |
| 189 | return NULL; | 527 | return NULL; |
| 190 | 528 | ||
| 191 | vmw_be->ttm.func = &vmw_ttm_func; | 529 | vmw_be->dma_ttm.ttm.func = &vmw_ttm_func; |
| 192 | vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev); | 530 | vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev); |
| 193 | 531 | ||
| 194 | if (ttm_tt_init(&vmw_be->ttm, bdev, size, page_flags, dummy_read_page)) { | 532 | if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent) |
| 195 | kfree(vmw_be); | 533 | ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags, |
| 196 | return NULL; | 534 | dummy_read_page); |
| 197 | } | 535 | else |
| 198 | 536 | ret = ttm_tt_init(&vmw_be->dma_ttm.ttm, bdev, size, page_flags, | |
| 199 | return &vmw_be->ttm; | 537 | dummy_read_page); |
| 538 | if (unlikely(ret != 0)) | ||
| 539 | goto out_no_init; | ||
| 540 | |||
| 541 | return &vmw_be->dma_ttm.ttm; | ||
| 542 | out_no_init: | ||
| 543 | kfree(vmw_be); | ||
| 544 | return NULL; | ||
| 200 | } | 545 | } |
| 201 | 546 | ||
| 202 | int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) | 547 | int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) |
| @@ -332,8 +677,8 @@ static int vmw_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible) | |||
| 332 | 677 | ||
| 333 | struct ttm_bo_driver vmw_bo_driver = { | 678 | struct ttm_bo_driver vmw_bo_driver = { |
| 334 | .ttm_tt_create = &vmw_ttm_tt_create, | 679 | .ttm_tt_create = &vmw_ttm_tt_create, |
| 335 | .ttm_tt_populate = &ttm_pool_populate, | 680 | .ttm_tt_populate = &vmw_ttm_populate, |
| 336 | .ttm_tt_unpopulate = &ttm_pool_unpopulate, | 681 | .ttm_tt_unpopulate = &vmw_ttm_unpopulate, |
| 337 | .invalidate_caches = vmw_invalidate_caches, | 682 | .invalidate_caches = vmw_invalidate_caches, |
| 338 | .init_mem_type = vmw_init_mem_type, | 683 | .init_mem_type = vmw_init_mem_type, |
| 339 | .evict_flags = vmw_evict_flags, | 684 | .evict_flags = vmw_evict_flags, |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 1a90f0a2f7e5..0b5c7818ebfb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <drm/ttm/ttm_bo_driver.h> | 32 | #include <drm/ttm/ttm_bo_driver.h> |
| 33 | #include <drm/ttm/ttm_object.h> | 33 | #include <drm/ttm/ttm_object.h> |
| 34 | #include <drm/ttm/ttm_module.h> | 34 | #include <drm/ttm/ttm_module.h> |
| 35 | #include <linux/dma_remapping.h> | ||
| 35 | 36 | ||
| 36 | #define VMWGFX_DRIVER_NAME "vmwgfx" | 37 | #define VMWGFX_DRIVER_NAME "vmwgfx" |
| 37 | #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" | 38 | #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" |
| @@ -185,6 +186,9 @@ static struct pci_device_id vmw_pci_id_list[] = { | |||
| 185 | MODULE_DEVICE_TABLE(pci, vmw_pci_id_list); | 186 | MODULE_DEVICE_TABLE(pci, vmw_pci_id_list); |
| 186 | 187 | ||
| 187 | static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON); | 188 | static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON); |
| 189 | static int vmw_force_iommu; | ||
| 190 | static int vmw_restrict_iommu; | ||
| 191 | static int vmw_force_coherent; | ||
| 188 | 192 | ||
| 189 | static int vmw_probe(struct pci_dev *, const struct pci_device_id *); | 193 | static int vmw_probe(struct pci_dev *, const struct pci_device_id *); |
| 190 | static void vmw_master_init(struct vmw_master *); | 194 | static void vmw_master_init(struct vmw_master *); |
| @@ -193,6 +197,13 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, | |||
| 193 | 197 | ||
| 194 | MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev"); | 198 | MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev"); |
| 195 | module_param_named(enable_fbdev, enable_fbdev, int, 0600); | 199 | module_param_named(enable_fbdev, enable_fbdev, int, 0600); |
| 200 | MODULE_PARM_DESC(force_dma_api, "Force using the DMA API for TTM pages"); | ||
| 201 | module_param_named(force_dma_api, vmw_force_iommu, int, 0600); | ||
| 202 | MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages"); | ||
| 203 | module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600); | ||
| 204 | MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages"); | ||
| 205 | module_param_named(force_coherent, vmw_force_coherent, int, 0600); | ||
| 206 | |||
| 196 | 207 | ||
| 197 | static void vmw_print_capabilities(uint32_t capabilities) | 208 | static void vmw_print_capabilities(uint32_t capabilities) |
| 198 | { | 209 | { |
| @@ -427,12 +438,78 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv) | |||
| 427 | dev_priv->initial_height = height; | 438 | dev_priv->initial_height = height; |
| 428 | } | 439 | } |
| 429 | 440 | ||
| 441 | /** | ||
| 442 | * vmw_dma_select_mode - Determine how DMA mappings should be set up for this | ||
| 443 | * system. | ||
| 444 | * | ||
| 445 | * @dev_priv: Pointer to a struct vmw_private | ||
| 446 | * | ||
| 447 | * This functions tries to determine the IOMMU setup and what actions | ||
| 448 | * need to be taken by the driver to make system pages visible to the | ||
| 449 | * device. | ||
| 450 | * If this function decides that DMA is not possible, it returns -EINVAL. | ||
| 451 | * The driver may then try to disable features of the device that require | ||
| 452 | * DMA. | ||
| 453 | */ | ||
| 454 | static int vmw_dma_select_mode(struct vmw_private *dev_priv) | ||
| 455 | { | ||
| 456 | const struct dma_map_ops *dma_ops = get_dma_ops(dev_priv->dev->dev); | ||
| 457 | static const char *names[vmw_dma_map_max] = { | ||
| 458 | [vmw_dma_phys] = "Using physical TTM page addresses.", | ||
| 459 | [vmw_dma_alloc_coherent] = "Using coherent TTM pages.", | ||
| 460 | [vmw_dma_map_populate] = "Keeping DMA mappings.", | ||
| 461 | [vmw_dma_map_bind] = "Giving up DMA mappings early."}; | ||
| 462 | |||
| 463 | #ifdef CONFIG_INTEL_IOMMU | ||
| 464 | if (intel_iommu_enabled) { | ||
| 465 | dev_priv->map_mode = vmw_dma_map_populate; | ||
| 466 | goto out_fixup; | ||
| 467 | } | ||
| 468 | #endif | ||
| 469 | |||
| 470 | if (!(vmw_force_iommu || vmw_force_coherent)) { | ||
| 471 | dev_priv->map_mode = vmw_dma_phys; | ||
| 472 | DRM_INFO("DMA map mode: %s\n", names[dev_priv->map_mode]); | ||
| 473 | return 0; | ||
| 474 | } | ||
| 475 | |||
| 476 | dev_priv->map_mode = vmw_dma_map_populate; | ||
| 477 | |||
| 478 | if (dma_ops->sync_single_for_cpu) | ||
| 479 | dev_priv->map_mode = vmw_dma_alloc_coherent; | ||
| 480 | #ifdef CONFIG_SWIOTLB | ||
| 481 | if (swiotlb_nr_tbl() == 0) | ||
| 482 | dev_priv->map_mode = vmw_dma_map_populate; | ||
| 483 | #endif | ||
| 484 | |||
| 485 | out_fixup: | ||
| 486 | if (dev_priv->map_mode == vmw_dma_map_populate && | ||
| 487 | vmw_restrict_iommu) | ||
| 488 | dev_priv->map_mode = vmw_dma_map_bind; | ||
| 489 | |||
| 490 | if (vmw_force_coherent) | ||
| 491 | dev_priv->map_mode = vmw_dma_alloc_coherent; | ||
| 492 | |||
| 493 | #if !defined(CONFIG_SWIOTLB) && !defined(CONFIG_INTEL_IOMMU) | ||
| 494 | /* | ||
| 495 | * No coherent page pool | ||
| 496 | */ | ||
| 497 | if (dev_priv->map_mode == vmw_dma_alloc_coherent) | ||
| 498 | return -EINVAL; | ||
| 499 | #endif | ||
| 500 | |||
| 501 | DRM_INFO("DMA map mode: %s\n", names[dev_priv->map_mode]); | ||
| 502 | |||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 430 | static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | 506 | static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) |
| 431 | { | 507 | { |
| 432 | struct vmw_private *dev_priv; | 508 | struct vmw_private *dev_priv; |
| 433 | int ret; | 509 | int ret; |
| 434 | uint32_t svga_id; | 510 | uint32_t svga_id; |
| 435 | enum vmw_res_type i; | 511 | enum vmw_res_type i; |
| 512 | bool refuse_dma = false; | ||
| 436 | 513 | ||
| 437 | dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); | 514 | dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); |
| 438 | if (unlikely(dev_priv == NULL)) { | 515 | if (unlikely(dev_priv == NULL)) { |
| @@ -481,6 +558,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
| 481 | } | 558 | } |
| 482 | 559 | ||
| 483 | dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); | 560 | dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); |
| 561 | ret = vmw_dma_select_mode(dev_priv); | ||
| 562 | if (unlikely(ret != 0)) { | ||
| 563 | DRM_INFO("Restricting capabilities due to IOMMU setup.\n"); | ||
| 564 | refuse_dma = true; | ||
| 565 | } | ||
| 484 | 566 | ||
| 485 | dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE); | 567 | dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE); |
| 486 | dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE); | 568 | dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE); |
| @@ -558,8 +640,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
| 558 | } | 640 | } |
| 559 | 641 | ||
| 560 | dev_priv->has_gmr = true; | 642 | dev_priv->has_gmr = true; |
| 561 | if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR, | 643 | if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || |
| 562 | dev_priv->max_gmr_ids) != 0) { | 644 | refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR, |
| 645 | dev_priv->max_gmr_ids) != 0) { | ||
| 563 | DRM_INFO("No GMR memory available. " | 646 | DRM_INFO("No GMR memory available. " |
| 564 | "Graphics memory resources are very limited.\n"); | 647 | "Graphics memory resources are very limited.\n"); |
| 565 | dev_priv->has_gmr = false; | 648 | dev_priv->has_gmr = false; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 150ec64af617..e401d5dbcb96 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
| @@ -177,6 +177,58 @@ struct vmw_res_cache_entry { | |||
| 177 | struct vmw_resource_val_node *node; | 177 | struct vmw_resource_val_node *node; |
| 178 | }; | 178 | }; |
| 179 | 179 | ||
| 180 | /** | ||
| 181 | * enum vmw_dma_map_mode - indicate how to perform TTM page dma mappings. | ||
| 182 | */ | ||
| 183 | enum vmw_dma_map_mode { | ||
| 184 | vmw_dma_phys, /* Use physical page addresses */ | ||
| 185 | vmw_dma_alloc_coherent, /* Use TTM coherent pages */ | ||
| 186 | vmw_dma_map_populate, /* Unmap from DMA just after unpopulate */ | ||
| 187 | vmw_dma_map_bind, /* Unmap from DMA just before unbind */ | ||
| 188 | vmw_dma_map_max | ||
| 189 | }; | ||
| 190 | |||
| 191 | /** | ||
| 192 | * struct vmw_sg_table - Scatter/gather table for binding, with additional | ||
| 193 | * device-specific information. | ||
| 194 | * | ||
| 195 | * @sgt: Pointer to a struct sg_table with binding information | ||
| 196 | * @num_regions: Number of regions with device-address contigous pages | ||
| 197 | */ | ||
| 198 | struct vmw_sg_table { | ||
| 199 | enum vmw_dma_map_mode mode; | ||
| 200 | struct page **pages; | ||
| 201 | const dma_addr_t *addrs; | ||
| 202 | struct sg_table *sgt; | ||
| 203 | unsigned long num_regions; | ||
| 204 | unsigned long num_pages; | ||
| 205 | }; | ||
| 206 | |||
| 207 | /** | ||
| 208 | * struct vmw_piter - Page iterator that iterates over a list of pages | ||
| 209 | * and DMA addresses that could be either a scatter-gather list or | ||
| 210 | * arrays | ||
| 211 | * | ||
| 212 | * @pages: Array of page pointers to the pages. | ||
| 213 | * @addrs: DMA addresses to the pages if coherent pages are used. | ||
| 214 | * @iter: Scatter-gather page iterator. Current position in SG list. | ||
| 215 | * @i: Current position in arrays. | ||
| 216 | * @num_pages: Number of pages total. | ||
| 217 | * @next: Function to advance the iterator. Returns false if past the list | ||
| 218 | * of pages, true otherwise. | ||
| 219 | * @dma_address: Function to return the DMA address of the current page. | ||
| 220 | */ | ||
| 221 | struct vmw_piter { | ||
| 222 | struct page **pages; | ||
| 223 | const dma_addr_t *addrs; | ||
| 224 | struct sg_page_iter iter; | ||
| 225 | unsigned long i; | ||
| 226 | unsigned long num_pages; | ||
| 227 | bool (*next)(struct vmw_piter *); | ||
| 228 | dma_addr_t (*dma_address)(struct vmw_piter *); | ||
| 229 | struct page *(*page)(struct vmw_piter *); | ||
| 230 | }; | ||
| 231 | |||
| 180 | struct vmw_sw_context{ | 232 | struct vmw_sw_context{ |
| 181 | struct drm_open_hash res_ht; | 233 | struct drm_open_hash res_ht; |
| 182 | bool res_ht_initialized; | 234 | bool res_ht_initialized; |
| @@ -358,6 +410,11 @@ struct vmw_private { | |||
| 358 | 410 | ||
| 359 | struct list_head res_lru[vmw_res_max]; | 411 | struct list_head res_lru[vmw_res_max]; |
| 360 | uint32_t used_memory_size; | 412 | uint32_t used_memory_size; |
| 413 | |||
| 414 | /* | ||
| 415 | * DMA mapping stuff. | ||
| 416 | */ | ||
| 417 | enum vmw_dma_map_mode map_mode; | ||
| 361 | }; | 418 | }; |
| 362 | 419 | ||
| 363 | static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res) | 420 | static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res) |
| @@ -405,7 +462,7 @@ void vmw_3d_resource_dec(struct vmw_private *dev_priv, bool hide_svga); | |||
| 405 | */ | 462 | */ |
| 406 | 463 | ||
| 407 | extern int vmw_gmr_bind(struct vmw_private *dev_priv, | 464 | extern int vmw_gmr_bind(struct vmw_private *dev_priv, |
| 408 | struct page *pages[], | 465 | const struct vmw_sg_table *vsgt, |
| 409 | unsigned long num_pages, | 466 | unsigned long num_pages, |
| 410 | int gmr_id); | 467 | int gmr_id); |
| 411 | extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id); | 468 | extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id); |
| @@ -568,6 +625,45 @@ extern struct ttm_placement vmw_evictable_placement; | |||
| 568 | extern struct ttm_placement vmw_srf_placement; | 625 | extern struct ttm_placement vmw_srf_placement; |
| 569 | extern struct ttm_bo_driver vmw_bo_driver; | 626 | extern struct ttm_bo_driver vmw_bo_driver; |
| 570 | extern int vmw_dma_quiescent(struct drm_device *dev); | 627 | extern int vmw_dma_quiescent(struct drm_device *dev); |
| 628 | extern void vmw_piter_start(struct vmw_piter *viter, | ||
| 629 | const struct vmw_sg_table *vsgt, | ||
| 630 | unsigned long p_offs); | ||
| 631 | |||
| 632 | /** | ||
| 633 | * vmw_piter_next - Advance the iterator one page. | ||
| 634 | * | ||
| 635 | * @viter: Pointer to the iterator to advance. | ||
| 636 | * | ||
| 637 | * Returns false if past the list of pages, true otherwise. | ||
| 638 | */ | ||
| 639 | static inline bool vmw_piter_next(struct vmw_piter *viter) | ||
| 640 | { | ||
| 641 | return viter->next(viter); | ||
| 642 | } | ||
| 643 | |||
| 644 | /** | ||
| 645 | * vmw_piter_dma_addr - Return the DMA address of the current page. | ||
| 646 | * | ||
| 647 | * @viter: Pointer to the iterator | ||
| 648 | * | ||
| 649 | * Returns the DMA address of the page pointed to by @viter. | ||
| 650 | */ | ||
| 651 | static inline dma_addr_t vmw_piter_dma_addr(struct vmw_piter *viter) | ||
| 652 | { | ||
| 653 | return viter->dma_address(viter); | ||
| 654 | } | ||
| 655 | |||
| 656 | /** | ||
| 657 | * vmw_piter_page - Return a pointer to the current page. | ||
| 658 | * | ||
| 659 | * @viter: Pointer to the iterator | ||
| 660 | * | ||
| 661 | * Returns the DMA address of the page pointed to by @viter. | ||
| 662 | */ | ||
| 663 | static inline struct page *vmw_piter_page(struct vmw_piter *viter) | ||
| 664 | { | ||
| 665 | return viter->page(viter); | ||
| 666 | } | ||
| 571 | 667 | ||
| 572 | /** | 668 | /** |
| 573 | * Command submission - vmwgfx_execbuf.c | 669 | * Command submission - vmwgfx_execbuf.c |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index 1a0bf07fe54b..6d0952366f91 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | |||
| @@ -32,9 +32,11 @@ | |||
| 32 | #define VMW_PPN_SIZE (sizeof(unsigned long)) | 32 | #define VMW_PPN_SIZE (sizeof(unsigned long)) |
| 33 | /* A future safe maximum remap size. */ | 33 | /* A future safe maximum remap size. */ |
| 34 | #define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE) | 34 | #define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE) |
| 35 | #define DMA_ADDR_INVALID ((dma_addr_t) 0) | ||
| 36 | #define DMA_PAGE_INVALID 0UL | ||
| 35 | 37 | ||
| 36 | static int vmw_gmr2_bind(struct vmw_private *dev_priv, | 38 | static int vmw_gmr2_bind(struct vmw_private *dev_priv, |
| 37 | struct page *pages[], | 39 | struct vmw_piter *iter, |
| 38 | unsigned long num_pages, | 40 | unsigned long num_pages, |
| 39 | int gmr_id) | 41 | int gmr_id) |
| 40 | { | 42 | { |
| @@ -81,11 +83,13 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv, | |||
| 81 | 83 | ||
| 82 | for (i = 0; i < nr; ++i) { | 84 | for (i = 0; i < nr; ++i) { |
| 83 | if (VMW_PPN_SIZE <= 4) | 85 | if (VMW_PPN_SIZE <= 4) |
| 84 | *cmd = page_to_pfn(*pages++); | 86 | *cmd = vmw_piter_dma_addr(iter) >> PAGE_SHIFT; |
| 85 | else | 87 | else |
| 86 | *((uint64_t *)cmd) = page_to_pfn(*pages++); | 88 | *((uint64_t *)cmd) = vmw_piter_dma_addr(iter) >> |
| 89 | PAGE_SHIFT; | ||
| 87 | 90 | ||
| 88 | cmd += VMW_PPN_SIZE / sizeof(*cmd); | 91 | cmd += VMW_PPN_SIZE / sizeof(*cmd); |
| 92 | vmw_piter_next(iter); | ||
| 89 | } | 93 | } |
| 90 | 94 | ||
| 91 | num_pages -= nr; | 95 | num_pages -= nr; |
| @@ -120,22 +124,54 @@ static void vmw_gmr2_unbind(struct vmw_private *dev_priv, | |||
| 120 | vmw_fifo_commit(dev_priv, define_size); | 124 | vmw_fifo_commit(dev_priv, define_size); |
| 121 | } | 125 | } |
| 122 | 126 | ||
| 127 | |||
| 128 | static void vmw_gmr_free_descriptors(struct device *dev, dma_addr_t desc_dma, | ||
| 129 | struct list_head *desc_pages) | ||
| 130 | { | ||
| 131 | struct page *page, *next; | ||
| 132 | struct svga_guest_mem_descriptor *page_virtual; | ||
| 133 | unsigned int desc_per_page = PAGE_SIZE / | ||
| 134 | sizeof(struct svga_guest_mem_descriptor) - 1; | ||
| 135 | |||
| 136 | if (list_empty(desc_pages)) | ||
| 137 | return; | ||
| 138 | |||
| 139 | list_for_each_entry_safe(page, next, desc_pages, lru) { | ||
| 140 | list_del_init(&page->lru); | ||
| 141 | |||
| 142 | if (likely(desc_dma != DMA_ADDR_INVALID)) { | ||
| 143 | dma_unmap_page(dev, desc_dma, PAGE_SIZE, | ||
| 144 | DMA_TO_DEVICE); | ||
| 145 | } | ||
| 146 | |||
| 147 | page_virtual = kmap_atomic(page); | ||
| 148 | desc_dma = page_virtual[desc_per_page].ppn << PAGE_SHIFT; | ||
| 149 | kunmap_atomic(page_virtual); | ||
| 150 | |||
| 151 | __free_page(page); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 123 | /** | 155 | /** |
| 124 | * FIXME: Adjust to the ttm lowmem / highmem storage to minimize | 156 | * FIXME: Adjust to the ttm lowmem / highmem storage to minimize |
| 125 | * the number of used descriptors. | 157 | * the number of used descriptors. |
| 158 | * | ||
| 126 | */ | 159 | */ |
| 127 | 160 | ||
| 128 | static int vmw_gmr_build_descriptors(struct list_head *desc_pages, | 161 | static int vmw_gmr_build_descriptors(struct device *dev, |
| 129 | struct page *pages[], | 162 | struct list_head *desc_pages, |
| 130 | unsigned long num_pages) | 163 | struct vmw_piter *iter, |
| 164 | unsigned long num_pages, | ||
| 165 | dma_addr_t *first_dma) | ||
| 131 | { | 166 | { |
| 132 | struct page *page, *next; | 167 | struct page *page; |
| 133 | struct svga_guest_mem_descriptor *page_virtual = NULL; | 168 | struct svga_guest_mem_descriptor *page_virtual = NULL; |
| 134 | struct svga_guest_mem_descriptor *desc_virtual = NULL; | 169 | struct svga_guest_mem_descriptor *desc_virtual = NULL; |
| 135 | unsigned int desc_per_page; | 170 | unsigned int desc_per_page; |
| 136 | unsigned long prev_pfn; | 171 | unsigned long prev_pfn; |
| 137 | unsigned long pfn; | 172 | unsigned long pfn; |
| 138 | int ret; | 173 | int ret; |
| 174 | dma_addr_t desc_dma; | ||
| 139 | 175 | ||
| 140 | desc_per_page = PAGE_SIZE / | 176 | desc_per_page = PAGE_SIZE / |
| 141 | sizeof(struct svga_guest_mem_descriptor) - 1; | 177 | sizeof(struct svga_guest_mem_descriptor) - 1; |
| @@ -148,23 +184,12 @@ static int vmw_gmr_build_descriptors(struct list_head *desc_pages, | |||
| 148 | } | 184 | } |
| 149 | 185 | ||
| 150 | list_add_tail(&page->lru, desc_pages); | 186 | list_add_tail(&page->lru, desc_pages); |
| 151 | |||
| 152 | /* | ||
| 153 | * Point previous page terminating descriptor to this | ||
| 154 | * page before unmapping it. | ||
| 155 | */ | ||
| 156 | |||
| 157 | if (likely(page_virtual != NULL)) { | ||
| 158 | desc_virtual->ppn = page_to_pfn(page); | ||
| 159 | kunmap_atomic(page_virtual); | ||
| 160 | } | ||
| 161 | |||
| 162 | page_virtual = kmap_atomic(page); | 187 | page_virtual = kmap_atomic(page); |
| 163 | desc_virtual = page_virtual - 1; | 188 | desc_virtual = page_virtual - 1; |
| 164 | prev_pfn = ~(0UL); | 189 | prev_pfn = ~(0UL); |
| 165 | 190 | ||
| 166 | while (likely(num_pages != 0)) { | 191 | while (likely(num_pages != 0)) { |
| 167 | pfn = page_to_pfn(*pages); | 192 | pfn = vmw_piter_dma_addr(iter) >> PAGE_SHIFT; |
| 168 | 193 | ||
| 169 | if (pfn != prev_pfn + 1) { | 194 | if (pfn != prev_pfn + 1) { |
| 170 | 195 | ||
| @@ -181,104 +206,81 @@ static int vmw_gmr_build_descriptors(struct list_head *desc_pages, | |||
| 181 | } | 206 | } |
| 182 | prev_pfn = pfn; | 207 | prev_pfn = pfn; |
| 183 | --num_pages; | 208 | --num_pages; |
| 184 | ++pages; | 209 | vmw_piter_next(iter); |
| 185 | } | 210 | } |
| 186 | 211 | ||
| 187 | (++desc_virtual)->ppn = cpu_to_le32(0); | 212 | (++desc_virtual)->ppn = DMA_PAGE_INVALID; |
| 188 | desc_virtual->num_pages = cpu_to_le32(0); | 213 | desc_virtual->num_pages = cpu_to_le32(0); |
| 214 | kunmap_atomic(page_virtual); | ||
| 189 | } | 215 | } |
| 190 | 216 | ||
| 191 | if (likely(page_virtual != NULL)) | 217 | desc_dma = 0; |
| 218 | list_for_each_entry_reverse(page, desc_pages, lru) { | ||
| 219 | page_virtual = kmap_atomic(page); | ||
| 220 | page_virtual[desc_per_page].ppn = desc_dma >> PAGE_SHIFT; | ||
| 192 | kunmap_atomic(page_virtual); | 221 | kunmap_atomic(page_virtual); |
| 222 | desc_dma = dma_map_page(dev, page, 0, PAGE_SIZE, | ||
| 223 | DMA_TO_DEVICE); | ||
| 224 | |||
| 225 | if (unlikely(dma_mapping_error(dev, desc_dma))) | ||
| 226 | goto out_err; | ||
| 227 | } | ||
| 228 | *first_dma = desc_dma; | ||
| 193 | 229 | ||
| 194 | return 0; | 230 | return 0; |
| 195 | out_err: | 231 | out_err: |
| 196 | list_for_each_entry_safe(page, next, desc_pages, lru) { | 232 | vmw_gmr_free_descriptors(dev, DMA_ADDR_INVALID, desc_pages); |
| 197 | list_del_init(&page->lru); | ||
| 198 | __free_page(page); | ||
| 199 | } | ||
| 200 | return ret; | 233 | return ret; |
| 201 | } | 234 | } |
| 202 | 235 | ||
| 203 | static inline void vmw_gmr_free_descriptors(struct list_head *desc_pages) | ||
| 204 | { | ||
| 205 | struct page *page, *next; | ||
| 206 | |||
| 207 | list_for_each_entry_safe(page, next, desc_pages, lru) { | ||
| 208 | list_del_init(&page->lru); | ||
| 209 | __free_page(page); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv, | 236 | static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv, |
| 214 | int gmr_id, struct list_head *desc_pages) | 237 | int gmr_id, dma_addr_t desc_dma) |
| 215 | { | 238 | { |
| 216 | struct page *page; | ||
| 217 | |||
| 218 | if (unlikely(list_empty(desc_pages))) | ||
| 219 | return; | ||
| 220 | |||
| 221 | page = list_entry(desc_pages->next, struct page, lru); | ||
| 222 | |||
| 223 | mutex_lock(&dev_priv->hw_mutex); | 239 | mutex_lock(&dev_priv->hw_mutex); |
| 224 | 240 | ||
| 225 | vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id); | 241 | vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id); |
| 226 | wmb(); | 242 | wmb(); |
| 227 | vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, page_to_pfn(page)); | 243 | vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, desc_dma >> PAGE_SHIFT); |
| 228 | mb(); | 244 | mb(); |
| 229 | 245 | ||
| 230 | mutex_unlock(&dev_priv->hw_mutex); | 246 | mutex_unlock(&dev_priv->hw_mutex); |
| 231 | 247 | ||
| 232 | } | 248 | } |
| 233 | 249 | ||
| 234 | /** | ||
| 235 | * FIXME: Adjust to the ttm lowmem / highmem storage to minimize | ||
| 236 | * the number of used descriptors. | ||
| 237 | */ | ||
| 238 | |||
| 239 | static unsigned long vmw_gmr_count_descriptors(struct page *pages[], | ||
| 240 | unsigned long num_pages) | ||
| 241 | { | ||
| 242 | unsigned long prev_pfn = ~(0UL); | ||
| 243 | unsigned long pfn; | ||
| 244 | unsigned long descriptors = 0; | ||
| 245 | |||
| 246 | while (num_pages--) { | ||
| 247 | pfn = page_to_pfn(*pages++); | ||
| 248 | if (prev_pfn + 1 != pfn) | ||
| 249 | ++descriptors; | ||
| 250 | prev_pfn = pfn; | ||
| 251 | } | ||
| 252 | |||
| 253 | return descriptors; | ||
| 254 | } | ||
| 255 | |||
| 256 | int vmw_gmr_bind(struct vmw_private *dev_priv, | 250 | int vmw_gmr_bind(struct vmw_private *dev_priv, |
| 257 | struct page *pages[], | 251 | const struct vmw_sg_table *vsgt, |
| 258 | unsigned long num_pages, | 252 | unsigned long num_pages, |
| 259 | int gmr_id) | 253 | int gmr_id) |
| 260 | { | 254 | { |
| 261 | struct list_head desc_pages; | 255 | struct list_head desc_pages; |
| 256 | dma_addr_t desc_dma = 0; | ||
| 257 | struct device *dev = dev_priv->dev->dev; | ||
| 258 | struct vmw_piter data_iter; | ||
| 262 | int ret; | 259 | int ret; |
| 263 | 260 | ||
| 261 | vmw_piter_start(&data_iter, vsgt, 0); | ||
| 262 | |||
| 263 | if (unlikely(!vmw_piter_next(&data_iter))) | ||
| 264 | return 0; | ||
| 265 | |||
| 264 | if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) | 266 | if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) |
| 265 | return vmw_gmr2_bind(dev_priv, pages, num_pages, gmr_id); | 267 | return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id); |
| 266 | 268 | ||
| 267 | if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR))) | 269 | if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR))) |
| 268 | return -EINVAL; | 270 | return -EINVAL; |
| 269 | 271 | ||
| 270 | if (vmw_gmr_count_descriptors(pages, num_pages) > | 272 | if (vsgt->num_regions > dev_priv->max_gmr_descriptors) |
| 271 | dev_priv->max_gmr_descriptors) | ||
| 272 | return -EINVAL; | 273 | return -EINVAL; |
| 273 | 274 | ||
| 274 | INIT_LIST_HEAD(&desc_pages); | 275 | INIT_LIST_HEAD(&desc_pages); |
| 275 | 276 | ||
| 276 | ret = vmw_gmr_build_descriptors(&desc_pages, pages, num_pages); | 277 | ret = vmw_gmr_build_descriptors(dev, &desc_pages, &data_iter, |
| 278 | num_pages, &desc_dma); | ||
| 277 | if (unlikely(ret != 0)) | 279 | if (unlikely(ret != 0)) |
| 278 | return ret; | 280 | return ret; |
| 279 | 281 | ||
| 280 | vmw_gmr_fire_descriptors(dev_priv, gmr_id, &desc_pages); | 282 | vmw_gmr_fire_descriptors(dev_priv, gmr_id, desc_dma); |
| 281 | vmw_gmr_free_descriptors(&desc_pages); | 283 | vmw_gmr_free_descriptors(dev, desc_dma, &desc_pages); |
| 282 | 284 | ||
| 283 | return 0; | 285 | return 0; |
| 284 | } | 286 | } |
