Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/gma500: Make SGX MMU driver actually do something

Old MMU code never wrote PDs or PTEs to any registers. Now we do, and
that's a good start.

Signed-off-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>

+141 -137
+135 -129
drivers/gpu/drm/gma500/mmu.c
··· 59 59 spinlock_t lock; 60 60 61 61 atomic_t needs_tlbflush; 62 - 63 - uint8_t __iomem *register_map; 62 + atomic_t *msvdx_mmu_invaldc; 64 63 struct psb_mmu_pd *default_pd; 65 - /*uint32_t bif_ctrl;*/ 64 + uint32_t bif_ctrl; 66 65 int has_clflush; 67 66 int clflush_add; 68 67 unsigned long clflush_mask; 69 68 70 - struct drm_psb_private *dev_priv; 69 + struct drm_device *dev; 71 70 }; 72 71 73 72 struct psb_mmu_pd; ··· 101 102 return offset >> PSB_PDE_SHIFT; 102 103 } 103 104 105 + #if defined(CONFIG_X86) 104 106 static inline void psb_clflush(void *addr) 105 107 { 106 108 __asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory"); 107 109 } 108 110 109 - static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, 110 - void *addr) 111 + static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr) 111 112 { 112 113 if (!driver->has_clflush) 113 114 return; ··· 116 117 psb_clflush(addr); 117 118 mb(); 118 119 } 120 + #else 119 121 120 - static void psb_page_clflush(struct psb_mmu_driver *driver, struct page* page) 122 + static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr) 123 + {; 124 + } 125 + 126 + #endif 127 + 128 + static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, int force) 121 129 { 122 - uint32_t clflush_add = driver->clflush_add >> PAGE_SHIFT; 123 - uint32_t clflush_count = PAGE_SIZE / clflush_add; 124 - int i; 125 - uint8_t *clf; 130 + struct drm_device *dev = driver->dev; 131 + struct drm_psb_private *dev_priv = dev->dev_private; 126 132 127 - clf = kmap_atomic(page); 128 - mb(); 129 - for (i = 0; i < clflush_count; ++i) { 130 - psb_clflush(clf); 131 - clf += clflush_add; 133 + if (atomic_read(&driver->needs_tlbflush) || force) { 134 + uint32_t val = PSB_RSGX32(PSB_CR_BIF_CTRL); 135 + PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); 136 + 137 + /* Make sure data cache is turned off before enabling it */ 138 + wmb(); 139 + PSB_WSGX32(val & ~_PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); 140 + (void)PSB_RSGX32(PSB_CR_BIF_CTRL); 141 + if (driver->msvdx_mmu_invaldc) 142 + atomic_set(driver->msvdx_mmu_invaldc, 1); 132 143 } 133 - mb(); 134 - kunmap_atomic(clf); 135 - } 136 - 137 - static void psb_pages_clflush(struct psb_mmu_driver *driver, 138 - struct page *page[], unsigned long num_pages) 139 - { 140 - int i; 141 - 142 - if (!driver->has_clflush) 143 - return ; 144 - 145 - for (i = 0; i < num_pages; i++) 146 - psb_page_clflush(driver, *page++); 147 - } 148 - 149 - static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, 150 - int force) 151 - { 152 144 atomic_set(&driver->needs_tlbflush, 0); 153 145 } 154 146 147 + #if 0 155 148 static void psb_mmu_flush_pd(struct psb_mmu_driver *driver, int force) 156 149 { 157 150 down_write(&driver->sem); 158 151 psb_mmu_flush_pd_locked(driver, force); 159 152 up_write(&driver->sem); 160 153 } 154 + #endif 161 155 162 - void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot) 156 + void psb_mmu_flush(struct psb_mmu_driver *driver) 163 157 { 164 - if (rc_prot) 165 - down_write(&driver->sem); 166 - if (rc_prot) 167 - up_write(&driver->sem); 158 + struct drm_device *dev = driver->dev; 159 + struct drm_psb_private *dev_priv = dev->dev_private; 160 + uint32_t val; 161 + 162 + down_write(&driver->sem); 163 + val = PSB_RSGX32(PSB_CR_BIF_CTRL); 164 + if (atomic_read(&driver->needs_tlbflush)) 165 + PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); 166 + else 167 + PSB_WSGX32(val | _PSB_CB_CTRL_FLUSH, PSB_CR_BIF_CTRL); 168 + 169 + /* Make sure data cache is turned off and MMU is flushed before 170 + restoring bank interface control register */ 171 + wmb(); 172 + PSB_WSGX32(val & ~(_PSB_CB_CTRL_FLUSH | _PSB_CB_CTRL_INVALDC), 173 + PSB_CR_BIF_CTRL); 174 + (void)PSB_RSGX32(PSB_CR_BIF_CTRL); 175 + 176 + atomic_set(&driver->needs_tlbflush, 0); 177 + if (driver->msvdx_mmu_invaldc) 178 + atomic_set(driver->msvdx_mmu_invaldc, 1); 179 + up_write(&driver->sem); 168 180 } 169 181 170 182 void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context) 171 183 { 172 - /*ttm_tt_cache_flush(&pd->p, 1);*/ 173 - psb_pages_clflush(pd->driver, &pd->p, 1); 184 + struct drm_device *dev = pd->driver->dev; 185 + struct drm_psb_private *dev_priv = dev->dev_private; 186 + uint32_t offset = (hw_context == 0) ? PSB_CR_BIF_DIR_LIST_BASE0 : 187 + PSB_CR_BIF_DIR_LIST_BASE1 + hw_context * 4; 188 + 174 189 down_write(&pd->driver->sem); 190 + PSB_WSGX32(page_to_pfn(pd->p) << PAGE_SHIFT, offset); 175 191 wmb(); 176 192 psb_mmu_flush_pd_locked(pd->driver, 1); 177 193 pd->hw_context = hw_context; ··· 197 183 static inline unsigned long psb_pd_addr_end(unsigned long addr, 198 184 unsigned long end) 199 185 { 200 - 201 186 addr = (addr + PSB_PDE_MASK + 1) & ~PSB_PDE_MASK; 202 187 return (addr < end) ? addr : end; 203 188 } ··· 236 223 goto out_err3; 237 224 238 225 if (!trap_pagefaults) { 239 - pd->invalid_pde = 240 - psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), 241 - invalid_type); 242 - pd->invalid_pte = 243 - psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), 244 - invalid_type); 226 + pd->invalid_pde = psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), 227 + invalid_type); 228 + pd->invalid_pte = psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), 229 + invalid_type); 245 230 } else { 246 231 pd->invalid_pde = 0; 247 232 pd->invalid_pte = 0; ··· 290 279 void psb_mmu_free_pagedir(struct psb_mmu_pd *pd) 291 280 { 292 281 struct psb_mmu_driver *driver = pd->driver; 282 + struct drm_device *dev = driver->dev; 283 + struct drm_psb_private *dev_priv = dev->dev_private; 293 284 struct psb_mmu_pt *pt; 294 285 int i; 295 286 296 287 down_write(&driver->sem); 297 - if (pd->hw_context != -1) 288 + if (pd->hw_context != -1) { 289 + PSB_WSGX32(0, PSB_CR_BIF_DIR_LIST_BASE0 + pd->hw_context * 4); 298 290 psb_mmu_flush_pd_locked(driver, 1); 291 + } 299 292 300 293 /* Should take the spinlock here, but we don't need to do that 301 294 since we have the semaphore in write mode. */ ··· 346 331 for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) 347 332 *ptes++ = pd->invalid_pte; 348 333 349 - 334 + #if defined(CONFIG_X86) 350 335 if (pd->driver->has_clflush && pd->hw_context != -1) { 351 336 mb(); 352 337 for (i = 0; i < clflush_count; ++i) { ··· 355 340 } 356 341 mb(); 357 342 } 358 - 343 + #endif 359 344 kunmap_atomic(v); 360 345 spin_unlock(lock); 361 346 ··· 366 351 return pt; 367 352 } 368 353 369 - static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, 354 + struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, 370 355 unsigned long addr) 371 356 { 372 357 uint32_t index = psb_mmu_pd_index(addr); ··· 398 383 kunmap_atomic((void *) v); 399 384 400 385 if (pd->hw_context != -1) { 401 - psb_mmu_clflush(pd->driver, (void *) &v[index]); 386 + psb_mmu_clflush(pd->driver, (void *)&v[index]); 402 387 atomic_set(&pd->driver->needs_tlbflush, 1); 403 388 } 404 389 } ··· 435 420 pd->tables[pt->index] = NULL; 436 421 437 422 if (pd->hw_context != -1) { 438 - psb_mmu_clflush(pd->driver, 439 - (void *) &v[pt->index]); 423 + psb_mmu_clflush(pd->driver, (void *)&v[pt->index]); 440 424 atomic_set(&pd->driver->needs_tlbflush, 1); 441 425 } 442 426 kunmap_atomic(pt->v); ··· 446 432 spin_unlock(&pd->driver->lock); 447 433 } 448 434 449 - static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, 450 - unsigned long addr, uint32_t pte) 435 + static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, unsigned long addr, 436 + uint32_t pte) 451 437 { 452 438 pt->v[psb_mmu_pt_index(addr)] = pte; 453 439 } ··· 458 444 pt->v[psb_mmu_pt_index(addr)] = pt->pd->invalid_pte; 459 445 } 460 446 461 - 462 - void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, 463 - uint32_t mmu_offset, uint32_t gtt_start, 464 - uint32_t gtt_pages) 465 - { 466 - uint32_t *v; 467 - uint32_t start = psb_mmu_pd_index(mmu_offset); 468 - struct psb_mmu_driver *driver = pd->driver; 469 - int num_pages = gtt_pages; 470 - 471 - down_read(&driver->sem); 472 - spin_lock(&driver->lock); 473 - 474 - v = kmap_atomic(pd->p); 475 - v += start; 476 - 477 - while (gtt_pages--) { 478 - *v++ = gtt_start | pd->pd_mask; 479 - gtt_start += PAGE_SIZE; 480 - } 481 - 482 - /*ttm_tt_cache_flush(&pd->p, num_pages);*/ 483 - psb_pages_clflush(pd->driver, &pd->p, num_pages); 484 - kunmap_atomic(v); 485 - spin_unlock(&driver->lock); 486 - 487 - if (pd->hw_context != -1) 488 - atomic_set(&pd->driver->needs_tlbflush, 1); 489 - 490 - up_read(&pd->driver->sem); 491 - psb_mmu_flush_pd(pd->driver, 0); 492 - } 493 - 494 447 struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver) 495 448 { 496 449 struct psb_mmu_pd *pd; 497 450 498 - /* down_read(&driver->sem); */ 451 + down_read(&driver->sem); 499 452 pd = driver->default_pd; 500 - /* up_read(&driver->sem); */ 453 + up_read(&driver->sem); 501 454 502 455 return pd; 503 456 } 504 457 458 + /* Returns the physical address of the PD shared by sgx/msvdx */ 459 + uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver) 460 + { 461 + struct psb_mmu_pd *pd; 462 + 463 + pd = psb_mmu_get_default_pd(driver); 464 + return page_to_pfn(pd->p) << PAGE_SHIFT; 465 + } 466 + 505 467 void psb_mmu_driver_takedown(struct psb_mmu_driver *driver) 506 468 { 469 + struct drm_device *dev = driver->dev; 470 + struct drm_psb_private *dev_priv = dev->dev_private; 471 + 472 + PSB_WSGX32(driver->bif_ctrl, PSB_CR_BIF_CTRL); 507 473 psb_mmu_free_pagedir(driver->default_pd); 508 474 kfree(driver); 509 475 } 510 476 511 - struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, 512 - int trap_pagefaults, 513 - int invalid_type, 514 - struct drm_psb_private *dev_priv) 477 + struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, 478 + int trap_pagefaults, 479 + int invalid_type, 480 + atomic_t *msvdx_mmu_invaldc) 515 481 { 516 482 struct psb_mmu_driver *driver; 483 + struct drm_psb_private *dev_priv = dev->dev_private; 517 484 518 485 driver = kmalloc(sizeof(*driver), GFP_KERNEL); 519 486 520 487 if (!driver) 521 488 return NULL; 522 - driver->dev_priv = dev_priv; 523 489 490 + driver->dev = dev; 524 491 driver->default_pd = psb_mmu_alloc_pd(driver, trap_pagefaults, 525 492 invalid_type); 526 493 if (!driver->default_pd) ··· 510 515 spin_lock_init(&driver->lock); 511 516 init_rwsem(&driver->sem); 512 517 down_write(&driver->sem); 513 - driver->register_map = registers; 514 518 atomic_set(&driver->needs_tlbflush, 1); 519 + driver->msvdx_mmu_invaldc = msvdx_mmu_invaldc; 520 + 521 + driver->bif_ctrl = PSB_RSGX32(PSB_CR_BIF_CTRL); 522 + PSB_WSGX32(driver->bif_ctrl | _PSB_CB_CTRL_CLEAR_FAULT, 523 + PSB_CR_BIF_CTRL); 524 + PSB_WSGX32(driver->bif_ctrl & ~_PSB_CB_CTRL_CLEAR_FAULT, 525 + PSB_CR_BIF_CTRL); 515 526 516 527 driver->has_clflush = 0; 517 528 529 + #if defined(CONFIG_X86) 518 530 if (boot_cpu_has(X86_FEATURE_CLFLSH)) { 519 531 uint32_t tfms, misc, cap0, cap4, clflush_size; 520 532 521 533 /* 522 - * clflush size is determined at kernel setup for x86_64 523 - * but not for i386. We have to do it here. 534 + * clflush size is determined at kernel setup for x86_64 but not 535 + * for i386. We have to do it here. 524 536 */ 525 537 526 538 cpuid(0x00000001, &tfms, &misc, &cap0, &cap4); ··· 538 536 driver->clflush_mask = driver->clflush_add - 1; 539 537 driver->clflush_mask = ~driver->clflush_mask; 540 538 } 539 + #endif 541 540 542 541 up_write(&driver->sem); 543 542 return driver; ··· 548 545 return NULL; 549 546 } 550 547 551 - static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, 552 - unsigned long address, uint32_t num_pages, 553 - uint32_t desired_tile_stride, 548 + #if defined(CONFIG_X86) 549 + static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address, 550 + uint32_t num_pages, uint32_t desired_tile_stride, 554 551 uint32_t hw_tile_stride) 555 552 { 556 553 struct psb_mmu_pt *pt; ··· 564 561 unsigned long clflush_add = pd->driver->clflush_add; 565 562 unsigned long clflush_mask = pd->driver->clflush_mask; 566 563 567 - if (!pd->driver->has_clflush) { 568 - /*ttm_tt_cache_flush(&pd->p, num_pages);*/ 569 - psb_pages_clflush(pd->driver, &pd->p, num_pages); 564 + if (!pd->driver->has_clflush) 570 565 return; 571 - } 572 566 573 567 if (hw_tile_stride) 574 568 rows = num_pages / desired_tile_stride; ··· 586 586 if (!pt) 587 587 continue; 588 588 do { 589 - psb_clflush(&pt->v 590 - [psb_mmu_pt_index(addr)]); 591 - } while (addr += 592 - clflush_add, 589 + psb_clflush(&pt->v[psb_mmu_pt_index(addr)]); 590 + } while (addr += clflush_add, 593 591 (addr & clflush_mask) < next); 594 592 595 593 psb_mmu_pt_unmap_unlock(pt); ··· 596 598 } 597 599 mb(); 598 600 } 601 + #else 602 + static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address, 603 + uint32_t num_pages, uint32_t desired_tile_stride, 604 + uint32_t hw_tile_stride) 605 + { 606 + drm_ttm_cache_flush(); 607 + } 608 + #endif 599 609 600 610 void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, 601 611 unsigned long address, uint32_t num_pages) ··· 639 633 up_read(&pd->driver->sem); 640 634 641 635 if (pd->hw_context != -1) 642 - psb_mmu_flush(pd->driver, 0); 636 + psb_mmu_flush(pd->driver); 643 637 644 638 return; 645 639 } ··· 666 660 add = desired_tile_stride << PAGE_SHIFT; 667 661 row_add = hw_tile_stride << PAGE_SHIFT; 668 662 669 - /* down_read(&pd->driver->sem); */ 663 + down_read(&pd->driver->sem); 670 664 671 665 /* Make sure we only need to flush this processor's cache */ 672 666 ··· 694 688 psb_mmu_flush_ptes(pd, f_address, num_pages, 695 689 desired_tile_stride, hw_tile_stride); 696 690 697 - /* up_read(&pd->driver->sem); */ 691 + up_read(&pd->driver->sem); 698 692 699 693 if (pd->hw_context != -1) 700 - psb_mmu_flush(pd->driver, 0); 694 + psb_mmu_flush(pd->driver); 701 695 } 702 696 703 697 int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, ··· 710 704 unsigned long end; 711 705 unsigned long next; 712 706 unsigned long f_address = address; 713 - int ret = 0; 707 + int ret = -ENOMEM; 714 708 715 709 down_read(&pd->driver->sem); 716 710 ··· 732 726 psb_mmu_pt_unmap_unlock(pt); 733 727 734 728 } while (addr = next, next != end); 729 + ret = 0; 735 730 736 731 out: 737 732 if (pd->hw_context != -1) ··· 741 734 up_read(&pd->driver->sem); 742 735 743 736 if (pd->hw_context != -1) 744 - psb_mmu_flush(pd->driver, 1); 737 + psb_mmu_flush(pd->driver); 745 738 746 - return ret; 739 + return 0; 747 740 } 748 741 749 742 int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, 750 743 unsigned long address, uint32_t num_pages, 751 - uint32_t desired_tile_stride, 752 - uint32_t hw_tile_stride, int type) 744 + uint32_t desired_tile_stride, uint32_t hw_tile_stride, 745 + int type) 753 746 { 754 747 struct psb_mmu_pt *pt; 755 748 uint32_t rows = 1; ··· 761 754 unsigned long add; 762 755 unsigned long row_add; 763 756 unsigned long f_address = address; 764 - int ret = 0; 757 + int ret = -ENOMEM; 765 758 766 759 if (hw_tile_stride) { 767 760 if (num_pages % desired_tile_stride != 0) ··· 784 777 do { 785 778 next = psb_pd_addr_end(addr, end); 786 779 pt = psb_mmu_pt_alloc_map_lock(pd, addr); 787 - if (!pt) { 788 - ret = -ENOMEM; 780 + if (!pt) 789 781 goto out; 790 - } 791 782 do { 792 - pte = 793 - psb_mmu_mask_pte(page_to_pfn(*pages++), 794 - type); 783 + pte = psb_mmu_mask_pte(page_to_pfn(*pages++), 784 + type); 795 785 psb_mmu_set_pte(pt, addr, pte); 796 786 pt->count++; 797 787 } while (addr += PAGE_SIZE, addr < next); ··· 798 794 799 795 address += row_add; 800 796 } 797 + 798 + ret = 0; 801 799 out: 802 800 if (pd->hw_context != -1) 803 801 psb_mmu_flush_ptes(pd, f_address, num_pages, ··· 808 802 up_read(&pd->driver->sem); 809 803 810 804 if (pd->hw_context != -1) 811 - psb_mmu_flush(pd->driver, 1); 805 + psb_mmu_flush(pd->driver); 812 806 813 807 return ret; 814 808 }
+1 -3
drivers/gpu/drm/gma500/psb_drv.c
··· 347 347 if (ret) 348 348 goto out_err; 349 349 350 - dev_priv->mmu = psb_mmu_driver_init((void *)0, 351 - drm_psb_trap_pagefaults, 0, 352 - dev_priv); 350 + dev_priv->mmu = psb_mmu_driver_init(dev, drm_psb_trap_pagefaults, 0, 0); 353 351 if (!dev_priv->mmu) 354 352 goto out_err; 355 353
+5 -5
drivers/gpu/drm/gma500/psb_drv.h
··· 727 727 * MMU stuff. 728 728 */ 729 729 730 - extern struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, 731 - int trap_pagefaults, 732 - int invalid_type, 733 - struct drm_psb_private *dev_priv); 730 + extern struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, 731 + int trap_pagefaults, 732 + int invalid_type, 733 + atomic_t *msvdx_mmu_invaldc); 734 734 extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); 735 735 extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver 736 736 *driver); ··· 740 740 int trap_pagefaults, 741 741 int invalid_type); 742 742 extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); 743 - extern void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot); 743 + extern void psb_mmu_flush(struct psb_mmu_driver *driver); 744 744 extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, 745 745 unsigned long address, 746 746 uint32_t num_pages);