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