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

drm/mm: Support 4 GiB and larger ranges

The current implementation is limited by the number of addresses that
fit into an unsigned long. This causes problems on 32-bit Tegra where
unsigned long is 32-bit but drm_mm is used to manage an IOVA space of
4 GiB. Given the 32-bit limitation, the range is limited to 4 GiB - 1
(or 4 GiB - 4 KiB for page granularity).

This commit changes the start and size of the range to be an unsigned
64-bit integer, thus allowing much larger ranges to be supported.

[airlied: fix i915 warnings and coloring callback]

Signed-off-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Dave Airlie <airlied@redhat.com>

fixupo

authored by

Thierry Reding and committed by
Dave Airlie
440fd528 ed9ed50c

+110 -104
+79 -73
drivers/gpu/drm/drm_mm.c
··· 91 91 */ 92 92 93 93 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, 94 - unsigned long size, 94 + u64 size, 95 95 unsigned alignment, 96 96 unsigned long color, 97 97 enum drm_mm_search_flags flags); 98 98 static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, 99 - unsigned long size, 99 + u64 size, 100 100 unsigned alignment, 101 101 unsigned long color, 102 - unsigned long start, 103 - unsigned long end, 102 + u64 start, 103 + u64 end, 104 104 enum drm_mm_search_flags flags); 105 105 106 106 static void drm_mm_insert_helper(struct drm_mm_node *hole_node, 107 107 struct drm_mm_node *node, 108 - unsigned long size, unsigned alignment, 108 + u64 size, unsigned alignment, 109 109 unsigned long color, 110 110 enum drm_mm_allocator_flags flags) 111 111 { 112 112 struct drm_mm *mm = hole_node->mm; 113 - unsigned long hole_start = drm_mm_hole_node_start(hole_node); 114 - unsigned long hole_end = drm_mm_hole_node_end(hole_node); 115 - unsigned long adj_start = hole_start; 116 - unsigned long adj_end = hole_end; 113 + u64 hole_start = drm_mm_hole_node_start(hole_node); 114 + u64 hole_end = drm_mm_hole_node_end(hole_node); 115 + u64 adj_start = hole_start; 116 + u64 adj_end = hole_end; 117 117 118 118 BUG_ON(node->allocated); 119 119 ··· 124 124 adj_start = adj_end - size; 125 125 126 126 if (alignment) { 127 - unsigned tmp = adj_start % alignment; 128 - if (tmp) { 127 + u64 tmp = adj_start; 128 + unsigned rem; 129 + 130 + rem = do_div(tmp, alignment); 131 + if (rem) { 129 132 if (flags & DRM_MM_CREATE_TOP) 130 - adj_start -= tmp; 133 + adj_start -= rem; 131 134 else 132 - adj_start += alignment - tmp; 135 + adj_start += alignment - rem; 133 136 } 134 137 } 135 138 ··· 179 176 int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) 180 177 { 181 178 struct drm_mm_node *hole; 182 - unsigned long end = node->start + node->size; 183 - unsigned long hole_start; 184 - unsigned long hole_end; 179 + u64 end = node->start + node->size; 180 + u64 hole_start; 181 + u64 hole_end; 185 182 186 183 BUG_ON(node == NULL); 187 184 ··· 230 227 * 0 on success, -ENOSPC if there's no suitable hole. 231 228 */ 232 229 int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, 233 - unsigned long size, unsigned alignment, 230 + u64 size, unsigned alignment, 234 231 unsigned long color, 235 232 enum drm_mm_search_flags sflags, 236 233 enum drm_mm_allocator_flags aflags) ··· 249 246 250 247 static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, 251 248 struct drm_mm_node *node, 252 - unsigned long size, unsigned alignment, 249 + u64 size, unsigned alignment, 253 250 unsigned long color, 254 - unsigned long start, unsigned long end, 251 + u64 start, u64 end, 255 252 enum drm_mm_allocator_flags flags) 256 253 { 257 254 struct drm_mm *mm = hole_node->mm; 258 - unsigned long hole_start = drm_mm_hole_node_start(hole_node); 259 - unsigned long hole_end = drm_mm_hole_node_end(hole_node); 260 - unsigned long adj_start = hole_start; 261 - unsigned long adj_end = hole_end; 255 + u64 hole_start = drm_mm_hole_node_start(hole_node); 256 + u64 hole_end = drm_mm_hole_node_end(hole_node); 257 + u64 adj_start = hole_start; 258 + u64 adj_end = hole_end; 262 259 263 260 BUG_ON(!hole_node->hole_follows || node->allocated); 264 261 ··· 274 271 mm->color_adjust(hole_node, color, &adj_start, &adj_end); 275 272 276 273 if (alignment) { 277 - unsigned tmp = adj_start % alignment; 278 - if (tmp) { 274 + u64 tmp = adj_start; 275 + unsigned rem; 276 + 277 + rem = do_div(tmp, alignment); 278 + if (rem) { 279 279 if (flags & DRM_MM_CREATE_TOP) 280 - adj_start -= tmp; 280 + adj_start -= rem; 281 281 else 282 - adj_start += alignment - tmp; 282 + adj_start += alignment - rem; 283 283 } 284 284 } 285 285 ··· 330 324 * 0 on success, -ENOSPC if there's no suitable hole. 331 325 */ 332 326 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node, 333 - unsigned long size, unsigned alignment, 327 + u64 size, unsigned alignment, 334 328 unsigned long color, 335 - unsigned long start, unsigned long end, 329 + u64 start, u64 end, 336 330 enum drm_mm_search_flags sflags, 337 331 enum drm_mm_allocator_flags aflags) 338 332 { ··· 393 387 } 394 388 EXPORT_SYMBOL(drm_mm_remove_node); 395 389 396 - static int check_free_hole(unsigned long start, unsigned long end, 397 - unsigned long size, unsigned alignment) 390 + static int check_free_hole(u64 start, u64 end, u64 size, unsigned alignment) 398 391 { 399 392 if (end - start < size) 400 393 return 0; 401 394 402 395 if (alignment) { 403 - unsigned tmp = start % alignment; 396 + u64 tmp = start; 397 + unsigned rem; 398 + 399 + rem = do_div(tmp, alignment); 404 400 if (tmp) 405 - start += alignment - tmp; 401 + start += alignment - rem; 406 402 } 407 403 408 404 return end >= start + size; 409 405 } 410 406 411 407 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, 412 - unsigned long size, 408 + u64 size, 413 409 unsigned alignment, 414 410 unsigned long color, 415 411 enum drm_mm_search_flags flags) 416 412 { 417 413 struct drm_mm_node *entry; 418 414 struct drm_mm_node *best; 419 - unsigned long adj_start; 420 - unsigned long adj_end; 421 - unsigned long best_size; 415 + u64 adj_start; 416 + u64 adj_end; 417 + u64 best_size; 422 418 423 419 BUG_ON(mm->scanned_blocks); 424 420 ··· 429 421 430 422 __drm_mm_for_each_hole(entry, mm, adj_start, adj_end, 431 423 flags & DRM_MM_SEARCH_BELOW) { 432 - unsigned long hole_size = adj_end - adj_start; 424 + u64 hole_size = adj_end - adj_start; 433 425 434 426 if (mm->color_adjust) { 435 427 mm->color_adjust(entry, color, &adj_start, &adj_end); ··· 453 445 } 454 446 455 447 static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, 456 - unsigned long size, 448 + u64 size, 457 449 unsigned alignment, 458 450 unsigned long color, 459 - unsigned long start, 460 - unsigned long end, 451 + u64 start, 452 + u64 end, 461 453 enum drm_mm_search_flags flags) 462 454 { 463 455 struct drm_mm_node *entry; 464 456 struct drm_mm_node *best; 465 - unsigned long adj_start; 466 - unsigned long adj_end; 467 - unsigned long best_size; 457 + u64 adj_start; 458 + u64 adj_end; 459 + u64 best_size; 468 460 469 461 BUG_ON(mm->scanned_blocks); 470 462 ··· 473 465 474 466 __drm_mm_for_each_hole(entry, mm, adj_start, adj_end, 475 467 flags & DRM_MM_SEARCH_BELOW) { 476 - unsigned long hole_size = adj_end - adj_start; 468 + u64 hole_size = adj_end - adj_start; 477 469 478 470 if (adj_start < start) 479 471 adj_start = start; ··· 569 561 * adding/removing nodes to/from the scan list are allowed. 570 562 */ 571 563 void drm_mm_init_scan(struct drm_mm *mm, 572 - unsigned long size, 564 + u64 size, 573 565 unsigned alignment, 574 566 unsigned long color) 575 567 { ··· 602 594 * adding/removing nodes to/from the scan list are allowed. 603 595 */ 604 596 void drm_mm_init_scan_with_range(struct drm_mm *mm, 605 - unsigned long size, 597 + u64 size, 606 598 unsigned alignment, 607 599 unsigned long color, 608 - unsigned long start, 609 - unsigned long end) 600 + u64 start, 601 + u64 end) 610 602 { 611 603 mm->scan_color = color; 612 604 mm->scan_alignment = alignment; ··· 635 627 { 636 628 struct drm_mm *mm = node->mm; 637 629 struct drm_mm_node *prev_node; 638 - unsigned long hole_start, hole_end; 639 - unsigned long adj_start, adj_end; 630 + u64 hole_start, hole_end; 631 + u64 adj_start, adj_end; 640 632 641 633 mm->scanned_blocks++; 642 634 ··· 739 731 * 740 732 * Note that @mm must be cleared to 0 before calling this function. 741 733 */ 742 - void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) 734 + void drm_mm_init(struct drm_mm * mm, u64 start, u64 size) 743 735 { 744 736 INIT_LIST_HEAD(&mm->hole_stack); 745 737 mm->scanned_blocks = 0; ··· 774 766 } 775 767 EXPORT_SYMBOL(drm_mm_takedown); 776 768 777 - static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry, 778 - const char *prefix) 769 + static u64 drm_mm_debug_hole(struct drm_mm_node *entry, 770 + const char *prefix) 779 771 { 780 - unsigned long hole_start, hole_end, hole_size; 772 + u64 hole_start, hole_end, hole_size; 781 773 782 774 if (entry->hole_follows) { 783 775 hole_start = drm_mm_hole_node_start(entry); 784 776 hole_end = drm_mm_hole_node_end(entry); 785 777 hole_size = hole_end - hole_start; 786 - printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n", 787 - prefix, hole_start, hole_end, 788 - hole_size); 778 + pr_debug("%s %#llx-%#llx: %llu: free\n", prefix, hole_start, 779 + hole_end, hole_size); 789 780 return hole_size; 790 781 } 791 782 ··· 799 792 void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) 800 793 { 801 794 struct drm_mm_node *entry; 802 - unsigned long total_used = 0, total_free = 0, total = 0; 795 + u64 total_used = 0, total_free = 0, total = 0; 803 796 804 797 total_free += drm_mm_debug_hole(&mm->head_node, prefix); 805 798 806 799 drm_mm_for_each_node(entry, mm) { 807 - printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n", 808 - prefix, entry->start, entry->start + entry->size, 809 - entry->size); 800 + pr_debug("%s %#llx-%#llx: %llu: used\n", prefix, entry->start, 801 + entry->start + entry->size, entry->size); 810 802 total_used += entry->size; 811 803 total_free += drm_mm_debug_hole(entry, prefix); 812 804 } 813 805 total = total_free + total_used; 814 806 815 - printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total, 816 - total_used, total_free); 807 + pr_debug("%s total: %llu, used %llu free %llu\n", prefix, total, 808 + total_used, total_free); 817 809 } 818 810 EXPORT_SYMBOL(drm_mm_debug_table); 819 811 820 812 #if defined(CONFIG_DEBUG_FS) 821 - static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry) 813 + static u64 drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry) 822 814 { 823 - unsigned long hole_start, hole_end, hole_size; 815 + u64 hole_start, hole_end, hole_size; 824 816 825 817 if (entry->hole_follows) { 826 818 hole_start = drm_mm_hole_node_start(entry); 827 819 hole_end = drm_mm_hole_node_end(entry); 828 820 hole_size = hole_end - hole_start; 829 - seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n", 830 - hole_start, hole_end, hole_size); 821 + seq_printf(m, "%#llx-%#llx: %llu: free\n", hole_start, 822 + hole_end, hole_size); 831 823 return hole_size; 832 824 } 833 825 ··· 841 835 int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) 842 836 { 843 837 struct drm_mm_node *entry; 844 - unsigned long total_used = 0, total_free = 0, total = 0; 838 + u64 total_used = 0, total_free = 0, total = 0; 845 839 846 840 total_free += drm_mm_dump_hole(m, &mm->head_node); 847 841 848 842 drm_mm_for_each_node(entry, mm) { 849 - seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n", 850 - entry->start, entry->start + entry->size, 851 - entry->size); 843 + seq_printf(m, "%#016llx-%#016llx: %llu: used\n", entry->start, 844 + entry->start + entry->size, entry->size); 852 845 total_used += entry->size; 853 846 total_free += drm_mm_dump_hole(m, entry); 854 847 } 855 848 total = total_free + total_used; 856 849 857 - seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free); 850 + seq_printf(m, "total: %llu, used %llu free %llu\n", total, 851 + total_used, total_free); 858 852 return 0; 859 853 } 860 854 EXPORT_SYMBOL(drm_mm_dump_table);
+2 -2
drivers/gpu/drm/i915/i915_debugfs.c
··· 152 152 seq_puts(m, " (pp"); 153 153 else 154 154 seq_puts(m, " (g"); 155 - seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)", 155 + seq_printf(m, "gtt offset: %08llx, size: %08llx, type: %u)", 156 156 vma->node.start, vma->node.size, 157 157 vma->ggtt_view.type); 158 158 } 159 159 if (obj->stolen) 160 - seq_printf(m, " (stolen: %08lx)", obj->stolen->start); 160 + seq_printf(m, " (stolen: %08llx)", obj->stolen->start); 161 161 if (obj->pin_mappable || obj->fault_mappable) { 162 162 char s[3], *t = s; 163 163 if (obj->pin_mappable)
+3 -3
drivers/gpu/drm/i915/i915_gem_gtt.c
··· 1145 1145 1146 1146 ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true); 1147 1147 1148 - DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n", 1148 + DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n", 1149 1149 ppgtt->node.size >> 20, 1150 1150 ppgtt->node.start / PAGE_SIZE); 1151 1151 ··· 1713 1713 1714 1714 static void i915_gtt_color_adjust(struct drm_mm_node *node, 1715 1715 unsigned long color, 1716 - unsigned long *start, 1717 - unsigned long *end) 1716 + u64 *start, 1717 + u64 *end) 1718 1718 { 1719 1719 if (node->color != color) 1720 1720 *start += 4096;
+26 -26
include/drm/drm_mm.h
··· 68 68 unsigned scanned_preceeds_hole : 1; 69 69 unsigned allocated : 1; 70 70 unsigned long color; 71 - unsigned long start; 72 - unsigned long size; 71 + u64 start; 72 + u64 size; 73 73 struct drm_mm *mm; 74 74 }; 75 75 ··· 82 82 unsigned int scan_check_range : 1; 83 83 unsigned scan_alignment; 84 84 unsigned long scan_color; 85 - unsigned long scan_size; 86 - unsigned long scan_hit_start; 87 - unsigned long scan_hit_end; 85 + u64 scan_size; 86 + u64 scan_hit_start; 87 + u64 scan_hit_end; 88 88 unsigned scanned_blocks; 89 - unsigned long scan_start; 90 - unsigned long scan_end; 89 + u64 scan_start; 90 + u64 scan_end; 91 91 struct drm_mm_node *prev_scanned_node; 92 92 93 93 void (*color_adjust)(struct drm_mm_node *node, unsigned long color, 94 - unsigned long *start, unsigned long *end); 94 + u64 *start, u64 *end); 95 95 }; 96 96 97 97 /** ··· 124 124 return mm->hole_stack.next; 125 125 } 126 126 127 - static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_node) 127 + static inline u64 __drm_mm_hole_node_start(struct drm_mm_node *hole_node) 128 128 { 129 129 return hole_node->start + hole_node->size; 130 130 } ··· 140 140 * Returns: 141 141 * Start of the subsequent hole. 142 142 */ 143 - static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node) 143 + static inline u64 drm_mm_hole_node_start(struct drm_mm_node *hole_node) 144 144 { 145 145 BUG_ON(!hole_node->hole_follows); 146 146 return __drm_mm_hole_node_start(hole_node); 147 147 } 148 148 149 - static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node) 149 + static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node) 150 150 { 151 151 return list_entry(hole_node->node_list.next, 152 152 struct drm_mm_node, node_list)->start; ··· 163 163 * Returns: 164 164 * End of the subsequent hole. 165 165 */ 166 - static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) 166 + static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node) 167 167 { 168 168 return __drm_mm_hole_node_end(hole_node); 169 169 } ··· 222 222 223 223 int drm_mm_insert_node_generic(struct drm_mm *mm, 224 224 struct drm_mm_node *node, 225 - unsigned long size, 225 + u64 size, 226 226 unsigned alignment, 227 227 unsigned long color, 228 228 enum drm_mm_search_flags sflags, ··· 245 245 */ 246 246 static inline int drm_mm_insert_node(struct drm_mm *mm, 247 247 struct drm_mm_node *node, 248 - unsigned long size, 248 + u64 size, 249 249 unsigned alignment, 250 250 enum drm_mm_search_flags flags) 251 251 { ··· 255 255 256 256 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, 257 257 struct drm_mm_node *node, 258 - unsigned long size, 258 + u64 size, 259 259 unsigned alignment, 260 260 unsigned long color, 261 - unsigned long start, 262 - unsigned long end, 261 + u64 start, 262 + u64 end, 263 263 enum drm_mm_search_flags sflags, 264 264 enum drm_mm_allocator_flags aflags); 265 265 /** ··· 282 282 */ 283 283 static inline int drm_mm_insert_node_in_range(struct drm_mm *mm, 284 284 struct drm_mm_node *node, 285 - unsigned long size, 285 + u64 size, 286 286 unsigned alignment, 287 - unsigned long start, 288 - unsigned long end, 287 + u64 start, 288 + u64 end, 289 289 enum drm_mm_search_flags flags) 290 290 { 291 291 return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, ··· 296 296 void drm_mm_remove_node(struct drm_mm_node *node); 297 297 void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); 298 298 void drm_mm_init(struct drm_mm *mm, 299 - unsigned long start, 300 - unsigned long size); 299 + u64 start, 300 + u64 size); 301 301 void drm_mm_takedown(struct drm_mm *mm); 302 302 bool drm_mm_clean(struct drm_mm *mm); 303 303 304 304 void drm_mm_init_scan(struct drm_mm *mm, 305 - unsigned long size, 305 + u64 size, 306 306 unsigned alignment, 307 307 unsigned long color); 308 308 void drm_mm_init_scan_with_range(struct drm_mm *mm, 309 - unsigned long size, 309 + u64 size, 310 310 unsigned alignment, 311 311 unsigned long color, 312 - unsigned long start, 313 - unsigned long end); 312 + u64 start, 313 + u64 end); 314 314 bool drm_mm_scan_add_block(struct drm_mm_node *node); 315 315 bool drm_mm_scan_remove_block(struct drm_mm_node *node); 316 316