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

Configure Feed

Select the types of activity you want to include in your feed.

at v5.12-rc7 683 lines 16 kB view raw
1/* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2/************************************************************************** 3 * 4 * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29#define pr_fmt(fmt) "[TTM] " fmt 30 31#include <drm/ttm/ttm_memory.h> 32#include <linux/spinlock.h> 33#include <linux/sched.h> 34#include <linux/wait.h> 35#include <linux/mm.h> 36#include <linux/module.h> 37#include <linux/slab.h> 38#include <linux/swap.h> 39#include <drm/ttm/ttm_pool.h> 40 41#include "ttm_module.h" 42 43#define TTM_MEMORY_ALLOC_RETRIES 4 44 45struct ttm_mem_global ttm_mem_glob; 46EXPORT_SYMBOL(ttm_mem_glob); 47 48struct ttm_mem_zone { 49 struct kobject kobj; 50 struct ttm_mem_global *glob; 51 const char *name; 52 uint64_t zone_mem; 53 uint64_t emer_mem; 54 uint64_t max_mem; 55 uint64_t swap_limit; 56 uint64_t used_mem; 57}; 58 59static struct attribute ttm_mem_sys = { 60 .name = "zone_memory", 61 .mode = S_IRUGO 62}; 63static struct attribute ttm_mem_emer = { 64 .name = "emergency_memory", 65 .mode = S_IRUGO | S_IWUSR 66}; 67static struct attribute ttm_mem_max = { 68 .name = "available_memory", 69 .mode = S_IRUGO | S_IWUSR 70}; 71static struct attribute ttm_mem_swap = { 72 .name = "swap_limit", 73 .mode = S_IRUGO | S_IWUSR 74}; 75static struct attribute ttm_mem_used = { 76 .name = "used_memory", 77 .mode = S_IRUGO 78}; 79 80static void ttm_mem_zone_kobj_release(struct kobject *kobj) 81{ 82 struct ttm_mem_zone *zone = 83 container_of(kobj, struct ttm_mem_zone, kobj); 84 85 pr_info("Zone %7s: Used memory at exit: %llu KiB\n", 86 zone->name, (unsigned long long)zone->used_mem >> 10); 87 kfree(zone); 88} 89 90static ssize_t ttm_mem_zone_show(struct kobject *kobj, 91 struct attribute *attr, 92 char *buffer) 93{ 94 struct ttm_mem_zone *zone = 95 container_of(kobj, struct ttm_mem_zone, kobj); 96 uint64_t val = 0; 97 98 spin_lock(&zone->glob->lock); 99 if (attr == &ttm_mem_sys) 100 val = zone->zone_mem; 101 else if (attr == &ttm_mem_emer) 102 val = zone->emer_mem; 103 else if (attr == &ttm_mem_max) 104 val = zone->max_mem; 105 else if (attr == &ttm_mem_swap) 106 val = zone->swap_limit; 107 else if (attr == &ttm_mem_used) 108 val = zone->used_mem; 109 spin_unlock(&zone->glob->lock); 110 111 return snprintf(buffer, PAGE_SIZE, "%llu\n", 112 (unsigned long long) val >> 10); 113} 114 115static void ttm_check_swapping(struct ttm_mem_global *glob); 116 117static ssize_t ttm_mem_zone_store(struct kobject *kobj, 118 struct attribute *attr, 119 const char *buffer, 120 size_t size) 121{ 122 struct ttm_mem_zone *zone = 123 container_of(kobj, struct ttm_mem_zone, kobj); 124 int chars; 125 unsigned long val; 126 uint64_t val64; 127 128 chars = sscanf(buffer, "%lu", &val); 129 if (chars == 0) 130 return size; 131 132 val64 = val; 133 val64 <<= 10; 134 135 spin_lock(&zone->glob->lock); 136 if (val64 > zone->zone_mem) 137 val64 = zone->zone_mem; 138 if (attr == &ttm_mem_emer) { 139 zone->emer_mem = val64; 140 if (zone->max_mem > val64) 141 zone->max_mem = val64; 142 } else if (attr == &ttm_mem_max) { 143 zone->max_mem = val64; 144 if (zone->emer_mem < val64) 145 zone->emer_mem = val64; 146 } else if (attr == &ttm_mem_swap) 147 zone->swap_limit = val64; 148 spin_unlock(&zone->glob->lock); 149 150 ttm_check_swapping(zone->glob); 151 152 return size; 153} 154 155static struct attribute *ttm_mem_zone_attrs[] = { 156 &ttm_mem_sys, 157 &ttm_mem_emer, 158 &ttm_mem_max, 159 &ttm_mem_swap, 160 &ttm_mem_used, 161 NULL 162}; 163 164static const struct sysfs_ops ttm_mem_zone_ops = { 165 .show = &ttm_mem_zone_show, 166 .store = &ttm_mem_zone_store 167}; 168 169static struct kobj_type ttm_mem_zone_kobj_type = { 170 .release = &ttm_mem_zone_kobj_release, 171 .sysfs_ops = &ttm_mem_zone_ops, 172 .default_attrs = ttm_mem_zone_attrs, 173}; 174 175static struct attribute ttm_mem_global_lower_mem_limit = { 176 .name = "lower_mem_limit", 177 .mode = S_IRUGO | S_IWUSR 178}; 179 180static ssize_t ttm_mem_global_show(struct kobject *kobj, 181 struct attribute *attr, 182 char *buffer) 183{ 184 struct ttm_mem_global *glob = 185 container_of(kobj, struct ttm_mem_global, kobj); 186 uint64_t val = 0; 187 188 spin_lock(&glob->lock); 189 val = glob->lower_mem_limit; 190 spin_unlock(&glob->lock); 191 /* convert from number of pages to KB */ 192 val <<= (PAGE_SHIFT - 10); 193 return snprintf(buffer, PAGE_SIZE, "%llu\n", 194 (unsigned long long) val); 195} 196 197static ssize_t ttm_mem_global_store(struct kobject *kobj, 198 struct attribute *attr, 199 const char *buffer, 200 size_t size) 201{ 202 int chars; 203 uint64_t val64; 204 unsigned long val; 205 struct ttm_mem_global *glob = 206 container_of(kobj, struct ttm_mem_global, kobj); 207 208 chars = sscanf(buffer, "%lu", &val); 209 if (chars == 0) 210 return size; 211 212 val64 = val; 213 /* convert from KB to number of pages */ 214 val64 >>= (PAGE_SHIFT - 10); 215 216 spin_lock(&glob->lock); 217 glob->lower_mem_limit = val64; 218 spin_unlock(&glob->lock); 219 220 return size; 221} 222 223static struct attribute *ttm_mem_global_attrs[] = { 224 &ttm_mem_global_lower_mem_limit, 225 NULL 226}; 227 228static const struct sysfs_ops ttm_mem_global_ops = { 229 .show = &ttm_mem_global_show, 230 .store = &ttm_mem_global_store, 231}; 232 233static struct kobj_type ttm_mem_glob_kobj_type = { 234 .sysfs_ops = &ttm_mem_global_ops, 235 .default_attrs = ttm_mem_global_attrs, 236}; 237 238static bool ttm_zones_above_swap_target(struct ttm_mem_global *glob, 239 bool from_wq, uint64_t extra) 240{ 241 unsigned int i; 242 struct ttm_mem_zone *zone; 243 uint64_t target; 244 245 for (i = 0; i < glob->num_zones; ++i) { 246 zone = glob->zones[i]; 247 248 if (from_wq) 249 target = zone->swap_limit; 250 else if (capable(CAP_SYS_ADMIN)) 251 target = zone->emer_mem; 252 else 253 target = zone->max_mem; 254 255 target = (extra > target) ? 0ULL : target; 256 257 if (zone->used_mem > target) 258 return true; 259 } 260 return false; 261} 262 263/* 264 * At this point we only support a single shrink callback. 265 * Extend this if needed, perhaps using a linked list of callbacks. 266 * Note that this function is reentrant: 267 * many threads may try to swap out at any given time. 268 */ 269 270static void ttm_shrink(struct ttm_mem_global *glob, bool from_wq, 271 uint64_t extra, struct ttm_operation_ctx *ctx) 272{ 273 int ret; 274 275 spin_lock(&glob->lock); 276 277 while (ttm_zones_above_swap_target(glob, from_wq, extra)) { 278 spin_unlock(&glob->lock); 279 ret = ttm_bo_swapout(ctx); 280 spin_lock(&glob->lock); 281 if (unlikely(ret != 0)) 282 break; 283 } 284 285 spin_unlock(&glob->lock); 286} 287 288static void ttm_shrink_work(struct work_struct *work) 289{ 290 struct ttm_operation_ctx ctx = { 291 .interruptible = false, 292 .no_wait_gpu = false 293 }; 294 struct ttm_mem_global *glob = 295 container_of(work, struct ttm_mem_global, work); 296 297 ttm_shrink(glob, true, 0ULL, &ctx); 298} 299 300static int ttm_mem_init_kernel_zone(struct ttm_mem_global *glob, 301 const struct sysinfo *si) 302{ 303 struct ttm_mem_zone *zone = kzalloc(sizeof(*zone), GFP_KERNEL); 304 uint64_t mem; 305 int ret; 306 307 if (unlikely(!zone)) 308 return -ENOMEM; 309 310 mem = si->totalram - si->totalhigh; 311 mem *= si->mem_unit; 312 313 zone->name = "kernel"; 314 zone->zone_mem = mem; 315 zone->max_mem = mem >> 1; 316 zone->emer_mem = (mem >> 1) + (mem >> 2); 317 zone->swap_limit = zone->max_mem - (mem >> 3); 318 zone->used_mem = 0; 319 zone->glob = glob; 320 glob->zone_kernel = zone; 321 ret = kobject_init_and_add( 322 &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); 323 if (unlikely(ret != 0)) { 324 kobject_put(&zone->kobj); 325 return ret; 326 } 327 glob->zones[glob->num_zones++] = zone; 328 return 0; 329} 330 331#ifdef CONFIG_HIGHMEM 332static int ttm_mem_init_highmem_zone(struct ttm_mem_global *glob, 333 const struct sysinfo *si) 334{ 335 struct ttm_mem_zone *zone; 336 uint64_t mem; 337 int ret; 338 339 if (si->totalhigh == 0) 340 return 0; 341 342 zone = kzalloc(sizeof(*zone), GFP_KERNEL); 343 if (unlikely(!zone)) 344 return -ENOMEM; 345 346 mem = si->totalram; 347 mem *= si->mem_unit; 348 349 zone->name = "highmem"; 350 zone->zone_mem = mem; 351 zone->max_mem = mem >> 1; 352 zone->emer_mem = (mem >> 1) + (mem >> 2); 353 zone->swap_limit = zone->max_mem - (mem >> 3); 354 zone->used_mem = 0; 355 zone->glob = glob; 356 glob->zone_highmem = zone; 357 ret = kobject_init_and_add( 358 &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, "%s", 359 zone->name); 360 if (unlikely(ret != 0)) { 361 kobject_put(&zone->kobj); 362 return ret; 363 } 364 glob->zones[glob->num_zones++] = zone; 365 return 0; 366} 367#else 368static int ttm_mem_init_dma32_zone(struct ttm_mem_global *glob, 369 const struct sysinfo *si) 370{ 371 struct ttm_mem_zone *zone = kzalloc(sizeof(*zone), GFP_KERNEL); 372 uint64_t mem; 373 int ret; 374 375 if (unlikely(!zone)) 376 return -ENOMEM; 377 378 mem = si->totalram; 379 mem *= si->mem_unit; 380 381 /** 382 * No special dma32 zone needed. 383 */ 384 385 if (mem <= ((uint64_t) 1ULL << 32)) { 386 kfree(zone); 387 return 0; 388 } 389 390 /* 391 * Limit max dma32 memory to 4GB for now 392 * until we can figure out how big this 393 * zone really is. 394 */ 395 396 mem = ((uint64_t) 1ULL << 32); 397 zone->name = "dma32"; 398 zone->zone_mem = mem; 399 zone->max_mem = mem >> 1; 400 zone->emer_mem = (mem >> 1) + (mem >> 2); 401 zone->swap_limit = zone->max_mem - (mem >> 3); 402 zone->used_mem = 0; 403 zone->glob = glob; 404 glob->zone_dma32 = zone; 405 ret = kobject_init_and_add( 406 &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name); 407 if (unlikely(ret != 0)) { 408 kobject_put(&zone->kobj); 409 return ret; 410 } 411 glob->zones[glob->num_zones++] = zone; 412 return 0; 413} 414#endif 415 416int ttm_mem_global_init(struct ttm_mem_global *glob) 417{ 418 struct sysinfo si; 419 int ret; 420 int i; 421 struct ttm_mem_zone *zone; 422 423 spin_lock_init(&glob->lock); 424 glob->swap_queue = create_singlethread_workqueue("ttm_swap"); 425 INIT_WORK(&glob->work, ttm_shrink_work); 426 ret = kobject_init_and_add( 427 &glob->kobj, &ttm_mem_glob_kobj_type, ttm_get_kobj(), "memory_accounting"); 428 if (unlikely(ret != 0)) { 429 kobject_put(&glob->kobj); 430 return ret; 431 } 432 433 si_meminfo(&si); 434 435 /* set it as 0 by default to keep original behavior of OOM */ 436 glob->lower_mem_limit = 0; 437 438 ret = ttm_mem_init_kernel_zone(glob, &si); 439 if (unlikely(ret != 0)) 440 goto out_no_zone; 441#ifdef CONFIG_HIGHMEM 442 ret = ttm_mem_init_highmem_zone(glob, &si); 443 if (unlikely(ret != 0)) 444 goto out_no_zone; 445#else 446 ret = ttm_mem_init_dma32_zone(glob, &si); 447 if (unlikely(ret != 0)) 448 goto out_no_zone; 449#endif 450 for (i = 0; i < glob->num_zones; ++i) { 451 zone = glob->zones[i]; 452 pr_info("Zone %7s: Available graphics memory: %llu KiB\n", 453 zone->name, (unsigned long long)zone->max_mem >> 10); 454 } 455 ttm_pool_mgr_init(glob->zone_kernel->max_mem/(2*PAGE_SIZE)); 456 return 0; 457out_no_zone: 458 ttm_mem_global_release(glob); 459 return ret; 460} 461 462void ttm_mem_global_release(struct ttm_mem_global *glob) 463{ 464 struct ttm_mem_zone *zone; 465 unsigned int i; 466 467 /* let the page allocator first stop the shrink work. */ 468 ttm_pool_mgr_fini(); 469 470 flush_workqueue(glob->swap_queue); 471 destroy_workqueue(glob->swap_queue); 472 glob->swap_queue = NULL; 473 for (i = 0; i < glob->num_zones; ++i) { 474 zone = glob->zones[i]; 475 kobject_del(&zone->kobj); 476 kobject_put(&zone->kobj); 477 } 478 kobject_del(&glob->kobj); 479 kobject_put(&glob->kobj); 480 memset(glob, 0, sizeof(*glob)); 481} 482 483static void ttm_check_swapping(struct ttm_mem_global *glob) 484{ 485 bool needs_swapping = false; 486 unsigned int i; 487 struct ttm_mem_zone *zone; 488 489 spin_lock(&glob->lock); 490 for (i = 0; i < glob->num_zones; ++i) { 491 zone = glob->zones[i]; 492 if (zone->used_mem > zone->swap_limit) { 493 needs_swapping = true; 494 break; 495 } 496 } 497 498 spin_unlock(&glob->lock); 499 500 if (unlikely(needs_swapping)) 501 (void)queue_work(glob->swap_queue, &glob->work); 502 503} 504 505static void ttm_mem_global_free_zone(struct ttm_mem_global *glob, 506 struct ttm_mem_zone *single_zone, 507 uint64_t amount) 508{ 509 unsigned int i; 510 struct ttm_mem_zone *zone; 511 512 spin_lock(&glob->lock); 513 for (i = 0; i < glob->num_zones; ++i) { 514 zone = glob->zones[i]; 515 if (single_zone && zone != single_zone) 516 continue; 517 zone->used_mem -= amount; 518 } 519 spin_unlock(&glob->lock); 520} 521 522void ttm_mem_global_free(struct ttm_mem_global *glob, 523 uint64_t amount) 524{ 525 return ttm_mem_global_free_zone(glob, glob->zone_kernel, amount); 526} 527EXPORT_SYMBOL(ttm_mem_global_free); 528 529/* 530 * check if the available mem is under lower memory limit 531 * 532 * a. if no swap disk at all or free swap space is under swap_mem_limit 533 * but available system mem is bigger than sys_mem_limit, allow TTM 534 * allocation; 535 * 536 * b. if the available system mem is less than sys_mem_limit but free 537 * swap disk is bigger than swap_mem_limit, allow TTM allocation. 538 */ 539bool 540ttm_check_under_lowerlimit(struct ttm_mem_global *glob, 541 uint64_t num_pages, 542 struct ttm_operation_ctx *ctx) 543{ 544 int64_t available; 545 546 /* We allow over commit during suspend */ 547 if (ctx->force_alloc) 548 return false; 549 550 available = get_nr_swap_pages() + si_mem_available(); 551 available -= num_pages; 552 if (available < glob->lower_mem_limit) 553 return true; 554 555 return false; 556} 557 558static int ttm_mem_global_reserve(struct ttm_mem_global *glob, 559 struct ttm_mem_zone *single_zone, 560 uint64_t amount, bool reserve) 561{ 562 uint64_t limit; 563 int ret = -ENOMEM; 564 unsigned int i; 565 struct ttm_mem_zone *zone; 566 567 spin_lock(&glob->lock); 568 for (i = 0; i < glob->num_zones; ++i) { 569 zone = glob->zones[i]; 570 if (single_zone && zone != single_zone) 571 continue; 572 573 limit = (capable(CAP_SYS_ADMIN)) ? 574 zone->emer_mem : zone->max_mem; 575 576 if (zone->used_mem > limit) 577 goto out_unlock; 578 } 579 580 if (reserve) { 581 for (i = 0; i < glob->num_zones; ++i) { 582 zone = glob->zones[i]; 583 if (single_zone && zone != single_zone) 584 continue; 585 zone->used_mem += amount; 586 } 587 } 588 589 ret = 0; 590out_unlock: 591 spin_unlock(&glob->lock); 592 ttm_check_swapping(glob); 593 594 return ret; 595} 596 597 598static int ttm_mem_global_alloc_zone(struct ttm_mem_global *glob, 599 struct ttm_mem_zone *single_zone, 600 uint64_t memory, 601 struct ttm_operation_ctx *ctx) 602{ 603 int count = TTM_MEMORY_ALLOC_RETRIES; 604 605 while (unlikely(ttm_mem_global_reserve(glob, 606 single_zone, 607 memory, true) 608 != 0)) { 609 if (ctx->no_wait_gpu) 610 return -ENOMEM; 611 if (unlikely(count-- == 0)) 612 return -ENOMEM; 613 ttm_shrink(glob, false, memory + (memory >> 2) + 16, ctx); 614 } 615 616 return 0; 617} 618 619int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory, 620 struct ttm_operation_ctx *ctx) 621{ 622 /** 623 * Normal allocations of kernel memory are registered in 624 * the kernel zone. 625 */ 626 627 return ttm_mem_global_alloc_zone(glob, glob->zone_kernel, memory, ctx); 628} 629EXPORT_SYMBOL(ttm_mem_global_alloc); 630 631int ttm_mem_global_alloc_page(struct ttm_mem_global *glob, 632 struct page *page, uint64_t size, 633 struct ttm_operation_ctx *ctx) 634{ 635 struct ttm_mem_zone *zone = NULL; 636 637 /** 638 * Page allocations may be registed in a single zone 639 * only if highmem or !dma32. 640 */ 641 642#ifdef CONFIG_HIGHMEM 643 if (PageHighMem(page) && glob->zone_highmem != NULL) 644 zone = glob->zone_highmem; 645#else 646 if (glob->zone_dma32 && page_to_pfn(page) > 0x00100000UL) 647 zone = glob->zone_kernel; 648#endif 649 return ttm_mem_global_alloc_zone(glob, zone, size, ctx); 650} 651 652void ttm_mem_global_free_page(struct ttm_mem_global *glob, struct page *page, 653 uint64_t size) 654{ 655 struct ttm_mem_zone *zone = NULL; 656 657#ifdef CONFIG_HIGHMEM 658 if (PageHighMem(page) && glob->zone_highmem != NULL) 659 zone = glob->zone_highmem; 660#else 661 if (glob->zone_dma32 && page_to_pfn(page) > 0x00100000UL) 662 zone = glob->zone_kernel; 663#endif 664 ttm_mem_global_free_zone(glob, zone, size); 665} 666 667size_t ttm_round_pot(size_t size) 668{ 669 if ((size & (size - 1)) == 0) 670 return size; 671 else if (size > PAGE_SIZE) 672 return PAGE_ALIGN(size); 673 else { 674 size_t tmp_size = 4; 675 676 while (tmp_size < size) 677 tmp_size <<= 1; 678 679 return tmp_size; 680 } 681 return 0; 682} 683EXPORT_SYMBOL(ttm_round_pot);