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