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