15718399fSFrançois Tigeot /* 25718399fSFrançois Tigeot * Copyright (c) Red Hat Inc. 35718399fSFrançois Tigeot 45718399fSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 55718399fSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 65718399fSFrançois Tigeot * to deal in the Software without restriction, including without limitation 75718399fSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sub license, 85718399fSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 95718399fSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 105718399fSFrançois Tigeot * 115718399fSFrançois Tigeot * The above copyright notice and this permission notice (including the 125718399fSFrançois Tigeot * next paragraph) shall be included in all copies or substantial portions 135718399fSFrançois Tigeot * of the Software. 145718399fSFrançois Tigeot * 155718399fSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 165718399fSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 175718399fSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 185718399fSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 195718399fSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 205718399fSFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 215718399fSFrançois Tigeot * DEALINGS IN THE SOFTWARE. 225718399fSFrançois Tigeot * 235718399fSFrançois Tigeot * Authors: Dave Airlie <airlied@redhat.com> 245718399fSFrançois Tigeot * Jerome Glisse <jglisse@redhat.com> 255718399fSFrançois Tigeot * Pauli Nieminen <suokkos@gmail.com> 265718399fSFrançois Tigeot */ 275718399fSFrançois Tigeot /* 285718399fSFrançois Tigeot * Copyright (c) 2013 The FreeBSD Foundation 295718399fSFrançois Tigeot * All rights reserved. 305718399fSFrançois Tigeot * 315718399fSFrançois Tigeot * Portions of this software were developed by Konstantin Belousov 325718399fSFrançois Tigeot * <kib@FreeBSD.org> under sponsorship from the FreeBSD Foundation. 335718399fSFrançois Tigeot */ 345718399fSFrançois Tigeot 355718399fSFrançois Tigeot /* simple list based uncached page pool 365718399fSFrançois Tigeot * - Pool collects resently freed pages for reuse 375718399fSFrançois Tigeot * - Use page->lru to keep a free list 385718399fSFrançois Tigeot * - doesn't track currently in use pages 395718399fSFrançois Tigeot */ 405718399fSFrançois Tigeot 410bece63dSImre Vadasz #define pr_fmt(fmt) "[TTM] " fmt 420bece63dSImre Vadasz 436af927c2SFrançois Tigeot #include <linux/list.h> 446af927c2SFrançois Tigeot #include <linux/spinlock.h> 456af927c2SFrançois Tigeot #include <linux/highmem.h> 466af927c2SFrançois Tigeot #include <linux/mm_types.h> 476af927c2SFrançois Tigeot #include <linux/module.h> 486af927c2SFrançois Tigeot #include <linux/mm.h> 496af927c2SFrançois Tigeot #include <linux/seq_file.h> /* for seq_printf */ 506af927c2SFrançois Tigeot #include <linux/dma-mapping.h> 515718399fSFrançois Tigeot 526af927c2SFrançois Tigeot #include <linux/atomic.h> 536af927c2SFrançois Tigeot 54216f7a2cSFrançois Tigeot #include <drm/ttm/ttm_bo_driver.h> 55216f7a2cSFrançois Tigeot #include <drm/ttm/ttm_page_alloc.h> 565718399fSFrançois Tigeot 576af927c2SFrançois Tigeot #include <sys/eventhandler.h> 58f16f9121SMatthew Dillon #include <vm/vm_page2.h> 596af927c2SFrançois Tigeot 60d78d3a22SFrançois Tigeot #if IS_ENABLED(CONFIG_AGP) 615718399fSFrançois Tigeot #include <asm/agp.h> 625718399fSFrançois Tigeot #endif 63*a85cb24fSFrançois Tigeot #ifdef CONFIG_X86 64*a85cb24fSFrançois Tigeot #include <asm/set_memory.h> 65*a85cb24fSFrançois Tigeot #endif 665718399fSFrançois Tigeot 67f0bba3d1SFrançois Tigeot #define NUM_PAGES_TO_ALLOC (PAGE_SIZE/sizeof(struct page *)) 685718399fSFrançois Tigeot #define SMALL_ALLOCATION 16 695718399fSFrançois Tigeot #define FREE_ALL_PAGES (~0U) 705718399fSFrançois Tigeot /* times are in msecs */ 715718399fSFrançois Tigeot #define PAGE_FREE_INTERVAL 1000 725718399fSFrançois Tigeot 735718399fSFrançois Tigeot /** 745718399fSFrançois Tigeot * struct ttm_page_pool - Pool to reuse recently allocated uc/wc pages. 755718399fSFrançois Tigeot * 765718399fSFrançois Tigeot * @lock: Protects the shared pool from concurrnet access. Must be used with 775718399fSFrançois Tigeot * irqsave/irqrestore variants because pool allocator maybe called from 785718399fSFrançois Tigeot * delayed work. 795718399fSFrançois Tigeot * @fill_lock: Prevent concurrent calls to fill. 805718399fSFrançois Tigeot * @list: Pool of free uc/wc pages for fast reuse. 815718399fSFrançois Tigeot * @gfp_flags: Flags to pass for alloc_page. 825718399fSFrançois Tigeot * @npages: Number of pages in pool. 835718399fSFrançois Tigeot */ 845718399fSFrançois Tigeot struct ttm_page_pool { 855718399fSFrançois Tigeot struct lock lock; 865718399fSFrançois Tigeot bool fill_lock; 875718399fSFrançois Tigeot struct pglist list; 886af927c2SFrançois Tigeot gfp_t gfp_flags; 895718399fSFrançois Tigeot unsigned npages; 905718399fSFrançois Tigeot char *name; 915718399fSFrançois Tigeot unsigned long nfrees; 925718399fSFrançois Tigeot unsigned long nrefills; 935718399fSFrançois Tigeot }; 945718399fSFrançois Tigeot 955718399fSFrançois Tigeot /** 965718399fSFrançois Tigeot * Limits for the pool. They are handled without locks because only place where 975718399fSFrançois Tigeot * they may change is in sysfs store. They won't have immediate effect anyway 985718399fSFrançois Tigeot * so forcing serialization to access them is pointless. 995718399fSFrançois Tigeot */ 1005718399fSFrançois Tigeot 1015718399fSFrançois Tigeot struct ttm_pool_opts { 1025718399fSFrançois Tigeot unsigned alloc_size; 1035718399fSFrançois Tigeot unsigned max_size; 1045718399fSFrançois Tigeot unsigned small; 1055718399fSFrançois Tigeot }; 1065718399fSFrançois Tigeot 1075718399fSFrançois Tigeot #define NUM_POOLS 4 1085718399fSFrançois Tigeot 1095718399fSFrançois Tigeot /** 1105718399fSFrançois Tigeot * struct ttm_pool_manager - Holds memory pools for fst allocation 1115718399fSFrançois Tigeot * 1125718399fSFrançois Tigeot * Manager is read only object for pool code so it doesn't need locking. 1135718399fSFrançois Tigeot * 1145718399fSFrançois Tigeot * @free_interval: minimum number of jiffies between freeing pages from pool. 1155718399fSFrançois Tigeot * @page_alloc_inited: reference counting for pool allocation. 1165718399fSFrançois Tigeot * @work: Work that is used to shrink the pool. Work is only run when there is 1175718399fSFrançois Tigeot * some pages to free. 1185718399fSFrançois Tigeot * @small_allocation: Limit in number of pages what is small allocation. 1195718399fSFrançois Tigeot * 1205718399fSFrançois Tigeot * @pools: All pool objects in use. 1215718399fSFrançois Tigeot **/ 1225718399fSFrançois Tigeot struct ttm_pool_manager { 1233a2096e8SFrançois Tigeot struct kobject kobj; 12443e748b9SFrançois Tigeot struct shrinker mm_shrink; 1255718399fSFrançois Tigeot eventhandler_tag lowmem_handler; 1265718399fSFrançois Tigeot struct ttm_pool_opts options; 1275718399fSFrançois Tigeot 1285718399fSFrançois Tigeot union { 1296af927c2SFrançois Tigeot struct ttm_page_pool pools[NUM_POOLS]; 1306af927c2SFrançois Tigeot struct { 1316af927c2SFrançois Tigeot struct ttm_page_pool wc_pool; 1326af927c2SFrançois Tigeot struct ttm_page_pool uc_pool; 1336af927c2SFrançois Tigeot struct ttm_page_pool wc_pool_dma32; 1346af927c2SFrançois Tigeot struct ttm_page_pool uc_pool_dma32; 1355718399fSFrançois Tigeot } ; 1366af927c2SFrançois Tigeot }; 1376af927c2SFrançois Tigeot }; 1385718399fSFrançois Tigeot 1393a2096e8SFrançois Tigeot static struct attribute ttm_page_pool_max = { 1403a2096e8SFrançois Tigeot .name = "pool_max_size", 1413a2096e8SFrançois Tigeot .mode = S_IRUGO | S_IWUSR 1423a2096e8SFrançois Tigeot }; 1433a2096e8SFrançois Tigeot static struct attribute ttm_page_pool_small = { 1443a2096e8SFrançois Tigeot .name = "pool_small_allocation", 1453a2096e8SFrançois Tigeot .mode = S_IRUGO | S_IWUSR 1463a2096e8SFrançois Tigeot }; 1473a2096e8SFrançois Tigeot static struct attribute ttm_page_pool_alloc_size = { 1483a2096e8SFrançois Tigeot .name = "pool_allocation_size", 1493a2096e8SFrançois Tigeot .mode = S_IRUGO | S_IWUSR 1503a2096e8SFrançois Tigeot }; 1513a2096e8SFrançois Tigeot 1523a2096e8SFrançois Tigeot static struct attribute *ttm_pool_attrs[] = { 1533a2096e8SFrançois Tigeot &ttm_page_pool_max, 1543a2096e8SFrançois Tigeot &ttm_page_pool_small, 1553a2096e8SFrançois Tigeot &ttm_page_pool_alloc_size, 1563a2096e8SFrançois Tigeot NULL 1573a2096e8SFrançois Tigeot }; 1583a2096e8SFrançois Tigeot 1593a2096e8SFrançois Tigeot static void ttm_pool_kobj_release(struct kobject *kobj) 1605718399fSFrançois Tigeot { 1613a2096e8SFrançois Tigeot struct ttm_pool_manager *m = 1623a2096e8SFrançois Tigeot container_of(kobj, struct ttm_pool_manager, kobj); 163175896dfSzrj kfree(m); 1645718399fSFrançois Tigeot } 1655718399fSFrançois Tigeot 1663a2096e8SFrançois Tigeot static ssize_t ttm_pool_store(struct kobject *kobj, 1675718399fSFrançois Tigeot struct attribute *attr, const char *buffer, size_t size) 1685718399fSFrançois Tigeot { 1693a2096e8SFrançois Tigeot struct ttm_pool_manager *m = 1703a2096e8SFrançois Tigeot container_of(kobj, struct ttm_pool_manager, kobj); 1715718399fSFrançois Tigeot int chars; 1725718399fSFrançois Tigeot unsigned val; 1733a2096e8SFrançois Tigeot chars = ksscanf(buffer, "%u", &val); 1745718399fSFrançois Tigeot if (chars == 0) 1755718399fSFrançois Tigeot return size; 1765718399fSFrançois Tigeot 1775718399fSFrançois Tigeot /* Convert kb to number of pages */ 1785718399fSFrançois Tigeot val = val / (PAGE_SIZE >> 10); 1795718399fSFrançois Tigeot 1805718399fSFrançois Tigeot if (attr == &ttm_page_pool_max) 1815718399fSFrançois Tigeot m->options.max_size = val; 1825718399fSFrançois Tigeot else if (attr == &ttm_page_pool_small) 1835718399fSFrançois Tigeot m->options.small = val; 1845718399fSFrançois Tigeot else if (attr == &ttm_page_pool_alloc_size) { 1855718399fSFrançois Tigeot if (val > NUM_PAGES_TO_ALLOC*8) { 1865718399fSFrançois Tigeot pr_err("Setting allocation size to %lu is not allowed. Recommended size is %lu\n", 1875718399fSFrançois Tigeot NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7), 1885718399fSFrançois Tigeot NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); 1895718399fSFrançois Tigeot return size; 1905718399fSFrançois Tigeot } else if (val > NUM_PAGES_TO_ALLOC) { 1915718399fSFrançois Tigeot pr_warn("Setting allocation size to larger than %lu is not recommended\n", 1925718399fSFrançois Tigeot NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); 1935718399fSFrançois Tigeot } 1945718399fSFrançois Tigeot m->options.alloc_size = val; 1955718399fSFrançois Tigeot } 1965718399fSFrançois Tigeot 1975718399fSFrançois Tigeot return size; 1985718399fSFrançois Tigeot } 1995718399fSFrançois Tigeot 2003a2096e8SFrançois Tigeot static ssize_t ttm_pool_show(struct kobject *kobj, 2015718399fSFrançois Tigeot struct attribute *attr, char *buffer) 2025718399fSFrançois Tigeot { 2033a2096e8SFrançois Tigeot struct ttm_pool_manager *m = 2043a2096e8SFrançois Tigeot container_of(kobj, struct ttm_pool_manager, kobj); 2055718399fSFrançois Tigeot unsigned val = 0; 2065718399fSFrançois Tigeot 2075718399fSFrançois Tigeot if (attr == &ttm_page_pool_max) 2085718399fSFrançois Tigeot val = m->options.max_size; 2095718399fSFrançois Tigeot else if (attr == &ttm_page_pool_small) 2105718399fSFrançois Tigeot val = m->options.small; 2115718399fSFrançois Tigeot else if (attr == &ttm_page_pool_alloc_size) 2125718399fSFrançois Tigeot val = m->options.alloc_size; 2135718399fSFrançois Tigeot 2145718399fSFrançois Tigeot val = val * (PAGE_SIZE >> 10); 2155718399fSFrançois Tigeot 2163a2096e8SFrançois Tigeot return ksnprintf(buffer, PAGE_SIZE, "%u\n", val); 2175718399fSFrançois Tigeot } 2183a2096e8SFrançois Tigeot 2193a2096e8SFrançois Tigeot static const struct sysfs_ops ttm_pool_sysfs_ops = { 2203a2096e8SFrançois Tigeot .show = &ttm_pool_show, 2213a2096e8SFrançois Tigeot .store = &ttm_pool_store, 2223a2096e8SFrançois Tigeot }; 2233a2096e8SFrançois Tigeot 2243a2096e8SFrançois Tigeot static struct kobj_type ttm_pool_kobj_type = { 2253a2096e8SFrançois Tigeot .release = &ttm_pool_kobj_release, 2263a2096e8SFrançois Tigeot .sysfs_ops = &ttm_pool_sysfs_ops, 2273a2096e8SFrançois Tigeot .default_attrs = ttm_pool_attrs, 2283a2096e8SFrançois Tigeot }; 2295718399fSFrançois Tigeot 2305718399fSFrançois Tigeot static struct ttm_pool_manager *_manager; 2315718399fSFrançois Tigeot 23251933d89SFrançois Tigeot #ifndef CONFIG_X86 233f0bba3d1SFrançois Tigeot static int set_pages_array_wb(struct page **pages, int addrinarray) 2345718399fSFrançois Tigeot { 235d78d3a22SFrançois Tigeot #if IS_ENABLED(CONFIG_AGP) 2365718399fSFrançois Tigeot int i; 2375718399fSFrançois Tigeot 2386af927c2SFrançois Tigeot for (i = 0; i < addrinarray; i++) 239f0bba3d1SFrançois Tigeot unmap_page_from_agp(pages[i]); 2405718399fSFrançois Tigeot #endif 2415718399fSFrançois Tigeot return 0; 2425718399fSFrançois Tigeot } 2435718399fSFrançois Tigeot 244f0bba3d1SFrançois Tigeot static int set_pages_array_wc(struct page **pages, int addrinarray) 2455718399fSFrançois Tigeot { 246d78d3a22SFrançois Tigeot #if IS_ENABLED(CONFIG_AGP) 2475718399fSFrançois Tigeot int i; 2485718399fSFrançois Tigeot 2496af927c2SFrançois Tigeot for (i = 0; i < addrinarray; i++) 2505718399fSFrançois Tigeot map_page_into_agp(pages[i]); 2515718399fSFrançois Tigeot #endif 2525718399fSFrançois Tigeot return 0; 2535718399fSFrançois Tigeot } 2545718399fSFrançois Tigeot 255f0bba3d1SFrançois Tigeot static int set_pages_array_uc(struct page **pages, int addrinarray) 2565718399fSFrançois Tigeot { 257d78d3a22SFrançois Tigeot #if IS_ENABLED(CONFIG_AGP) 2585718399fSFrançois Tigeot int i; 2595718399fSFrançois Tigeot 2606af927c2SFrançois Tigeot for (i = 0; i < addrinarray; i++) 2615718399fSFrançois Tigeot map_page_into_agp(pages[i]); 2625718399fSFrançois Tigeot #endif 2635718399fSFrançois Tigeot return 0; 2645718399fSFrançois Tigeot } 26551933d89SFrançois Tigeot #endif 2665718399fSFrançois Tigeot 2675718399fSFrançois Tigeot /** 2685718399fSFrançois Tigeot * Select the right pool or requested caching state and ttm flags. */ 2695718399fSFrançois Tigeot static struct ttm_page_pool *ttm_get_pool(int flags, 2705718399fSFrançois Tigeot enum ttm_caching_state cstate) 2715718399fSFrançois Tigeot { 2725718399fSFrançois Tigeot int pool_index; 2735718399fSFrançois Tigeot 2745718399fSFrançois Tigeot if (cstate == tt_cached) 2755718399fSFrançois Tigeot return NULL; 2765718399fSFrançois Tigeot 2775718399fSFrançois Tigeot if (cstate == tt_wc) 2785718399fSFrançois Tigeot pool_index = 0x0; 2795718399fSFrançois Tigeot else 2805718399fSFrançois Tigeot pool_index = 0x1; 2815718399fSFrançois Tigeot 2825718399fSFrançois Tigeot if (flags & TTM_PAGE_FLAG_DMA32) 2835718399fSFrançois Tigeot pool_index |= 0x2; 2845718399fSFrançois Tigeot 2855718399fSFrançois Tigeot return &_manager->pools[pool_index]; 2865718399fSFrançois Tigeot } 2875718399fSFrançois Tigeot 2885718399fSFrançois Tigeot /* set memory back to wb and free the pages. */ 289f0bba3d1SFrançois Tigeot static void ttm_pages_put(struct page *pages[], unsigned npages) 2905718399fSFrançois Tigeot { 2915718399fSFrançois Tigeot unsigned i; 2925718399fSFrançois Tigeot if (set_pages_array_wb(pages, npages)) 2930bece63dSImre Vadasz pr_err("Failed to set %d pages to wb!\n", npages); 294f16f9121SMatthew Dillon for (i = 0; i < npages; ++i) { 295e5c1d8f1SFrançois Tigeot __free_page(pages[i]); 2965718399fSFrançois Tigeot } 297f16f9121SMatthew Dillon } 2985718399fSFrançois Tigeot 2995718399fSFrançois Tigeot static void ttm_pool_update_free_locked(struct ttm_page_pool *pool, 3005718399fSFrançois Tigeot unsigned freed_pages) 3015718399fSFrançois Tigeot { 3025718399fSFrançois Tigeot pool->npages -= freed_pages; 3035718399fSFrançois Tigeot pool->nfrees += freed_pages; 3045718399fSFrançois Tigeot } 3055718399fSFrançois Tigeot 3065718399fSFrançois Tigeot /** 3075718399fSFrançois Tigeot * Free pages from pool. 3085718399fSFrançois Tigeot * 3095718399fSFrançois Tigeot * To prevent hogging the ttm_swap process we only free NUM_PAGES_TO_ALLOC 3105718399fSFrançois Tigeot * number of pages in one go. 3115718399fSFrançois Tigeot * 3125718399fSFrançois Tigeot * @pool: to free the pages from 3135718399fSFrançois Tigeot * @free_all: If set to true will free all pages in pool 3147dcf36dcSFrançois Tigeot * @use_static: Safe to use static buffer 3155718399fSFrançois Tigeot **/ 3161cfef1a5SFrançois Tigeot static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free, 3177dcf36dcSFrançois Tigeot bool use_static) 3185718399fSFrançois Tigeot { 3197dcf36dcSFrançois Tigeot static struct page *static_buf[NUM_PAGES_TO_ALLOC]; 3206af927c2SFrançois Tigeot unsigned long irq_flags; 3216af927c2SFrançois Tigeot struct vm_page *p, *p1; 322f0bba3d1SFrançois Tigeot struct page **pages_to_free; 3235718399fSFrançois Tigeot unsigned freed_pages = 0, 3245718399fSFrançois Tigeot npages_to_free = nr_free; 3256f486c69SFrançois Tigeot unsigned i; 3265718399fSFrançois Tigeot 3275718399fSFrançois Tigeot if (NUM_PAGES_TO_ALLOC < nr_free) 3285718399fSFrançois Tigeot npages_to_free = NUM_PAGES_TO_ALLOC; 3295718399fSFrançois Tigeot 3307dcf36dcSFrançois Tigeot if (use_static) 3317dcf36dcSFrançois Tigeot pages_to_free = static_buf; 3327dcf36dcSFrançois Tigeot else 3337dcf36dcSFrançois Tigeot pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), 3347dcf36dcSFrançois Tigeot M_DRM, GFP_KERNEL); 3356af927c2SFrançois Tigeot if (!pages_to_free) { 3366af927c2SFrançois Tigeot pr_err("Failed to allocate memory for pool free operation\n"); 3376af927c2SFrançois Tigeot return 0; 3386af927c2SFrançois Tigeot } 3395718399fSFrançois Tigeot 3405718399fSFrançois Tigeot restart: 3416af927c2SFrançois Tigeot spin_lock_irqsave(&pool->lock, irq_flags); 3425718399fSFrançois Tigeot 3435718399fSFrançois Tigeot TAILQ_FOREACH_REVERSE_MUTABLE(p, &pool->list, pglist, pageq, p1) { 3445718399fSFrançois Tigeot if (freed_pages >= npages_to_free) 3455718399fSFrançois Tigeot break; 3465718399fSFrançois Tigeot 347f0bba3d1SFrançois Tigeot pages_to_free[freed_pages++] = (struct page *)p; 3485718399fSFrançois Tigeot /* We can only remove NUM_PAGES_TO_ALLOC at a time. */ 3495718399fSFrançois Tigeot if (freed_pages >= NUM_PAGES_TO_ALLOC) { 3505718399fSFrançois Tigeot /* remove range of pages from the pool */ 3516f486c69SFrançois Tigeot for (i = 0; i < freed_pages; i++) 352f0bba3d1SFrançois Tigeot TAILQ_REMOVE(&pool->list, (struct vm_page *)pages_to_free[i], pageq); 3535718399fSFrançois Tigeot 3545718399fSFrançois Tigeot ttm_pool_update_free_locked(pool, freed_pages); 3555718399fSFrançois Tigeot /** 3565718399fSFrançois Tigeot * Because changing page caching is costly 3575718399fSFrançois Tigeot * we unlock the pool to prevent stalling. 3585718399fSFrançois Tigeot */ 3596af927c2SFrançois Tigeot spin_unlock_irqrestore(&pool->lock, irq_flags); 3605718399fSFrançois Tigeot 3615718399fSFrançois Tigeot ttm_pages_put(pages_to_free, freed_pages); 3625718399fSFrançois Tigeot if (likely(nr_free != FREE_ALL_PAGES)) 3635718399fSFrançois Tigeot nr_free -= freed_pages; 3645718399fSFrançois Tigeot 3655718399fSFrançois Tigeot if (NUM_PAGES_TO_ALLOC >= nr_free) 3665718399fSFrançois Tigeot npages_to_free = nr_free; 3675718399fSFrançois Tigeot else 3685718399fSFrançois Tigeot npages_to_free = NUM_PAGES_TO_ALLOC; 3695718399fSFrançois Tigeot 3705718399fSFrançois Tigeot freed_pages = 0; 3715718399fSFrançois Tigeot 3725718399fSFrançois Tigeot /* free all so restart the processing */ 3735718399fSFrançois Tigeot if (nr_free) 3745718399fSFrançois Tigeot goto restart; 3755718399fSFrançois Tigeot 3765718399fSFrançois Tigeot /* Not allowed to fall through or break because 3775718399fSFrançois Tigeot * following context is inside spinlock while we are 3785718399fSFrançois Tigeot * outside here. 3795718399fSFrançois Tigeot */ 3805718399fSFrançois Tigeot goto out; 3815718399fSFrançois Tigeot 3825718399fSFrançois Tigeot } 3835718399fSFrançois Tigeot } 3845718399fSFrançois Tigeot 3855718399fSFrançois Tigeot /* remove range of pages from the pool */ 3865718399fSFrançois Tigeot if (freed_pages) { 3876f486c69SFrançois Tigeot for (i = 0; i < freed_pages; i++) 388f0bba3d1SFrançois Tigeot TAILQ_REMOVE(&pool->list, (struct vm_page *)pages_to_free[i], pageq); 3895718399fSFrançois Tigeot 3905718399fSFrançois Tigeot ttm_pool_update_free_locked(pool, freed_pages); 3915718399fSFrançois Tigeot nr_free -= freed_pages; 3925718399fSFrançois Tigeot } 3935718399fSFrançois Tigeot 3946af927c2SFrançois Tigeot spin_unlock_irqrestore(&pool->lock, irq_flags); 3955718399fSFrançois Tigeot 3965718399fSFrançois Tigeot if (freed_pages) 3975718399fSFrançois Tigeot ttm_pages_put(pages_to_free, freed_pages); 3985718399fSFrançois Tigeot out: 3997dcf36dcSFrançois Tigeot if (pages_to_free != static_buf) 4006af927c2SFrançois Tigeot kfree(pages_to_free); 4015718399fSFrançois Tigeot return nr_free; 4025718399fSFrançois Tigeot } 4035718399fSFrançois Tigeot 4045718399fSFrançois Tigeot /** 4055718399fSFrançois Tigeot * Callback for mm to request pool to reduce number of page held. 40643e748b9SFrançois Tigeot * 40743e748b9SFrançois Tigeot * XXX: (dchinner) Deadlock warning! 40843e748b9SFrançois Tigeot * 40943e748b9SFrançois Tigeot * This code is crying out for a shrinker per pool.... 4105718399fSFrançois Tigeot */ 41143e748b9SFrançois Tigeot static unsigned long 41243e748b9SFrançois Tigeot ttm_pool_shrink_scan(void *arg) 4135718399fSFrançois Tigeot { 4141cfef1a5SFrançois Tigeot #ifdef __DragonFly__ 4151cfef1a5SFrançois Tigeot static struct shrink_control __sc; 4161cfef1a5SFrançois Tigeot struct shrink_control *sc = &__sc; 4171cfef1a5SFrançois Tigeot #endif 4181cfef1a5SFrançois Tigeot static DEFINE_MUTEX(lock); 4191cfef1a5SFrançois Tigeot static unsigned start_pool; 4205718399fSFrançois Tigeot unsigned i; 4211cfef1a5SFrançois Tigeot unsigned pool_offset; 4225718399fSFrançois Tigeot struct ttm_page_pool *pool; 4235718399fSFrançois Tigeot int shrink_pages = 100; /* XXXKIB */ 42443e748b9SFrançois Tigeot unsigned long freed = 0; 4255718399fSFrançois Tigeot 4261cfef1a5SFrançois Tigeot #ifdef __DragonFly__ 4271cfef1a5SFrançois Tigeot sc->gfp_mask = M_WAITOK; 4281cfef1a5SFrançois Tigeot #endif 4291cfef1a5SFrançois Tigeot 4301cfef1a5SFrançois Tigeot if (!mutex_trylock(&lock)) 4311cfef1a5SFrançois Tigeot return SHRINK_STOP; 4321cfef1a5SFrançois Tigeot pool_offset = ++start_pool % NUM_POOLS; 4335718399fSFrançois Tigeot /* select start pool in round robin fashion */ 4345718399fSFrançois Tigeot for (i = 0; i < NUM_POOLS; ++i) { 4355718399fSFrançois Tigeot unsigned nr_free = shrink_pages; 4365718399fSFrançois Tigeot if (shrink_pages == 0) 4375718399fSFrançois Tigeot break; 4385718399fSFrançois Tigeot pool = &_manager->pools[(i + pool_offset)%NUM_POOLS]; 4397dcf36dcSFrançois Tigeot /* OK to use static buffer since global mutex is held. */ 4407dcf36dcSFrançois Tigeot shrink_pages = ttm_page_pool_free(pool, nr_free, true); 44143e748b9SFrançois Tigeot freed += nr_free - shrink_pages; 4425718399fSFrançois Tigeot } 4431cfef1a5SFrançois Tigeot mutex_unlock(&lock); 44443e748b9SFrançois Tigeot return freed; 44543e748b9SFrançois Tigeot } 44643e748b9SFrançois Tigeot 44743e748b9SFrançois Tigeot 44843e748b9SFrançois Tigeot static unsigned long 44943e748b9SFrançois Tigeot ttm_pool_shrink_count(struct shrinker *shrink, struct shrink_control *sc) 45043e748b9SFrançois Tigeot { 45143e748b9SFrançois Tigeot unsigned i; 45243e748b9SFrançois Tigeot unsigned long count = 0; 45343e748b9SFrançois Tigeot 45443e748b9SFrançois Tigeot for (i = 0; i < NUM_POOLS; ++i) 45543e748b9SFrançois Tigeot count += _manager->pools[i].npages; 45643e748b9SFrançois Tigeot 45743e748b9SFrançois Tigeot return count; 4585718399fSFrançois Tigeot } 4595718399fSFrançois Tigeot 4605718399fSFrançois Tigeot static void ttm_pool_mm_shrink_init(struct ttm_pool_manager *manager) 4615718399fSFrançois Tigeot { 46243e748b9SFrançois Tigeot manager->mm_shrink.count_objects = ttm_pool_shrink_count; 4635718399fSFrançois Tigeot manager->lowmem_handler = EVENTHANDLER_REGISTER(vm_lowmem, 46443e748b9SFrançois Tigeot ttm_pool_shrink_scan, manager, EVENTHANDLER_PRI_ANY); 4655718399fSFrançois Tigeot } 4665718399fSFrançois Tigeot 4675718399fSFrançois Tigeot static void ttm_pool_mm_shrink_fini(struct ttm_pool_manager *manager) 4685718399fSFrançois Tigeot { 4695718399fSFrançois Tigeot EVENTHANDLER_DEREGISTER(vm_lowmem, manager->lowmem_handler); 4705718399fSFrançois Tigeot } 4715718399fSFrançois Tigeot 472f0bba3d1SFrançois Tigeot static int ttm_set_pages_caching(struct page **pages, 4735718399fSFrançois Tigeot enum ttm_caching_state cstate, unsigned cpages) 4745718399fSFrançois Tigeot { 4755718399fSFrançois Tigeot int r = 0; 4765718399fSFrançois Tigeot /* Set page caching */ 4775718399fSFrançois Tigeot switch (cstate) { 4785718399fSFrançois Tigeot case tt_uncached: 4795718399fSFrançois Tigeot r = set_pages_array_uc(pages, cpages); 4805718399fSFrançois Tigeot if (r) 4810bece63dSImre Vadasz pr_err("Failed to set %d pages to uc!\n", cpages); 4825718399fSFrançois Tigeot break; 4835718399fSFrançois Tigeot case tt_wc: 4845718399fSFrançois Tigeot r = set_pages_array_wc(pages, cpages); 4855718399fSFrançois Tigeot if (r) 4860bece63dSImre Vadasz pr_err("Failed to set %d pages to wc!\n", cpages); 4875718399fSFrançois Tigeot break; 4885718399fSFrançois Tigeot default: 4895718399fSFrançois Tigeot break; 4905718399fSFrançois Tigeot } 4915718399fSFrançois Tigeot return r; 4925718399fSFrançois Tigeot } 4935718399fSFrançois Tigeot 4945718399fSFrançois Tigeot /** 4955718399fSFrançois Tigeot * Free pages the pages that failed to change the caching state. If there is 4965718399fSFrançois Tigeot * any pages that have changed their caching state already put them to the 4975718399fSFrançois Tigeot * pool. 4985718399fSFrançois Tigeot */ 4995718399fSFrançois Tigeot static void ttm_handle_caching_state_failure(struct pglist *pages, 5005718399fSFrançois Tigeot int ttm_flags, enum ttm_caching_state cstate, 501f0bba3d1SFrançois Tigeot struct page **failed_pages, unsigned cpages) 5025718399fSFrançois Tigeot { 5035718399fSFrançois Tigeot unsigned i; 5045718399fSFrançois Tigeot /* Failed pages have to be freed */ 5055718399fSFrançois Tigeot for (i = 0; i < cpages; ++i) { 506f0bba3d1SFrançois Tigeot TAILQ_REMOVE(pages, (struct vm_page *)failed_pages[i], pageq); 507e5c1d8f1SFrançois Tigeot __free_page(failed_pages[i]); 5085718399fSFrançois Tigeot } 5095718399fSFrançois Tigeot } 5105718399fSFrançois Tigeot 5115718399fSFrançois Tigeot /** 5125718399fSFrançois Tigeot * Allocate new pages with correct caching. 5135718399fSFrançois Tigeot * 5145718399fSFrançois Tigeot * This function is reentrant if caller updates count depending on number of 5155718399fSFrançois Tigeot * pages returned in pages array. 5165718399fSFrançois Tigeot */ 5176af927c2SFrançois Tigeot static int ttm_alloc_new_pages(struct pglist *pages, gfp_t gfp_flags, 5185718399fSFrançois Tigeot int ttm_flags, enum ttm_caching_state cstate, unsigned count) 5195718399fSFrançois Tigeot { 520f0bba3d1SFrançois Tigeot struct page **caching_array; 5216af927c2SFrançois Tigeot struct page *p; 5225718399fSFrançois Tigeot int r = 0; 5236af927c2SFrançois Tigeot unsigned i, cpages; 5245718399fSFrançois Tigeot unsigned max_cpages = min(count, 5256af927c2SFrançois Tigeot (unsigned)(PAGE_SIZE/sizeof(struct page *))); 5265718399fSFrançois Tigeot 5275718399fSFrançois Tigeot /* allocate array for page caching change */ 5286af927c2SFrançois Tigeot caching_array = kmalloc(max_cpages*sizeof(struct page *), M_DRM, M_WAITOK); 5296af927c2SFrançois Tigeot 5306af927c2SFrançois Tigeot if (!caching_array) { 5316af927c2SFrançois Tigeot pr_err("Unable to allocate table for new pages\n"); 5326af927c2SFrançois Tigeot return -ENOMEM; 5336af927c2SFrançois Tigeot } 5345718399fSFrançois Tigeot 5355718399fSFrançois Tigeot for (i = 0, cpages = 0; i < count; ++i) { 5366af927c2SFrançois Tigeot p = alloc_page(gfp_flags); 5376af927c2SFrançois Tigeot 5385718399fSFrançois Tigeot if (!p) { 5390bece63dSImre Vadasz pr_err("Unable to get page %u\n", i); 5405718399fSFrançois Tigeot 5415718399fSFrançois Tigeot /* store already allocated pages in the pool after 5425718399fSFrançois Tigeot * setting the caching state */ 5435718399fSFrançois Tigeot if (cpages) { 5445718399fSFrançois Tigeot r = ttm_set_pages_caching(caching_array, 5455718399fSFrançois Tigeot cstate, cpages); 5465718399fSFrançois Tigeot if (r) 5475718399fSFrançois Tigeot ttm_handle_caching_state_failure(pages, 5485718399fSFrançois Tigeot ttm_flags, cstate, 5495718399fSFrançois Tigeot caching_array, cpages); 5505718399fSFrançois Tigeot } 5515718399fSFrançois Tigeot r = -ENOMEM; 5525718399fSFrançois Tigeot goto out; 5535718399fSFrançois Tigeot } 5545718399fSFrançois Tigeot 5556af927c2SFrançois Tigeot #ifdef CONFIG_HIGHMEM 5565718399fSFrançois Tigeot /* gfp flags of highmem page should never be dma32 so we 5575718399fSFrançois Tigeot * we should be fine in such case 5585718399fSFrançois Tigeot */ 5595718399fSFrançois Tigeot if (!PageHighMem(p)) 5605718399fSFrançois Tigeot #endif 5615718399fSFrançois Tigeot { 5626af927c2SFrançois Tigeot caching_array[cpages++] = p; 5635718399fSFrançois Tigeot if (cpages == max_cpages) { 5645718399fSFrançois Tigeot 5655718399fSFrançois Tigeot r = ttm_set_pages_caching(caching_array, 5665718399fSFrançois Tigeot cstate, cpages); 5675718399fSFrançois Tigeot if (r) { 5685718399fSFrançois Tigeot ttm_handle_caching_state_failure(pages, 5695718399fSFrançois Tigeot ttm_flags, cstate, 5705718399fSFrançois Tigeot caching_array, cpages); 5715718399fSFrançois Tigeot goto out; 5725718399fSFrançois Tigeot } 5735718399fSFrançois Tigeot cpages = 0; 5745718399fSFrançois Tigeot } 5755718399fSFrançois Tigeot } 5765718399fSFrançois Tigeot 5776af927c2SFrançois Tigeot TAILQ_INSERT_HEAD(pages, (struct vm_page *)p, pageq); 5785718399fSFrançois Tigeot } 5795718399fSFrançois Tigeot 5805718399fSFrançois Tigeot if (cpages) { 5815718399fSFrançois Tigeot r = ttm_set_pages_caching(caching_array, cstate, cpages); 5825718399fSFrançois Tigeot if (r) 5835718399fSFrançois Tigeot ttm_handle_caching_state_failure(pages, 5845718399fSFrançois Tigeot ttm_flags, cstate, 5855718399fSFrançois Tigeot caching_array, cpages); 5865718399fSFrançois Tigeot } 5875718399fSFrançois Tigeot out: 5886af927c2SFrançois Tigeot kfree(caching_array); 5895718399fSFrançois Tigeot 5905718399fSFrançois Tigeot return r; 5915718399fSFrançois Tigeot } 5925718399fSFrançois Tigeot 5935718399fSFrançois Tigeot /** 5945718399fSFrançois Tigeot * Fill the given pool if there aren't enough pages and the requested number of 5955718399fSFrançois Tigeot * pages is small. 5965718399fSFrançois Tigeot */ 5975718399fSFrançois Tigeot static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool, 5986af927c2SFrançois Tigeot int ttm_flags, enum ttm_caching_state cstate, unsigned count, 5996af927c2SFrançois Tigeot unsigned long *irq_flags) 6005718399fSFrançois Tigeot { 6015718399fSFrançois Tigeot vm_page_t p; 6025718399fSFrançois Tigeot int r; 6035718399fSFrançois Tigeot unsigned cpages = 0; 6045718399fSFrançois Tigeot /** 6055718399fSFrançois Tigeot * Only allow one pool fill operation at a time. 6065718399fSFrançois Tigeot * If pool doesn't have enough pages for the allocation new pages are 6075718399fSFrançois Tigeot * allocated from outside of pool. 6085718399fSFrançois Tigeot */ 6095718399fSFrançois Tigeot if (pool->fill_lock) 6105718399fSFrançois Tigeot return; 6115718399fSFrançois Tigeot 6125718399fSFrançois Tigeot pool->fill_lock = true; 6135718399fSFrançois Tigeot 6145718399fSFrançois Tigeot /* If allocation request is small and there are not enough 6155718399fSFrançois Tigeot * pages in a pool we fill the pool up first. */ 6165718399fSFrançois Tigeot if (count < _manager->options.small 6175718399fSFrançois Tigeot && count > pool->npages) { 6185718399fSFrançois Tigeot struct pglist new_pages; 6195718399fSFrançois Tigeot unsigned alloc_size = _manager->options.alloc_size; 6205718399fSFrançois Tigeot 6215718399fSFrançois Tigeot /** 6225718399fSFrançois Tigeot * Can't change page caching if in irqsave context. We have to 6235718399fSFrançois Tigeot * drop the pool->lock. 6245718399fSFrançois Tigeot */ 6256af927c2SFrançois Tigeot spin_unlock_irqrestore(&pool->lock, *irq_flags); 6265718399fSFrançois Tigeot 6275718399fSFrançois Tigeot TAILQ_INIT(&new_pages); 6286af927c2SFrançois Tigeot r = ttm_alloc_new_pages(&new_pages, pool->gfp_flags, ttm_flags, 6296af927c2SFrançois Tigeot cstate, alloc_size); 6306af927c2SFrançois Tigeot spin_lock_irqsave(&pool->lock, *irq_flags); 6315718399fSFrançois Tigeot 6325718399fSFrançois Tigeot if (!r) { 6335718399fSFrançois Tigeot TAILQ_CONCAT(&pool->list, &new_pages, pageq); 6345718399fSFrançois Tigeot ++pool->nrefills; 6355718399fSFrançois Tigeot pool->npages += alloc_size; 6365718399fSFrançois Tigeot } else { 6370bece63dSImre Vadasz pr_err("Failed to fill pool (%p)\n", pool); 6385718399fSFrançois Tigeot /* If we have any pages left put them to the pool. */ 639*a85cb24fSFrançois Tigeot TAILQ_FOREACH(p, &new_pages, pageq) { 6405718399fSFrançois Tigeot ++cpages; 6415718399fSFrançois Tigeot } 6425718399fSFrançois Tigeot TAILQ_CONCAT(&pool->list, &new_pages, pageq); 6435718399fSFrançois Tigeot pool->npages += cpages; 6445718399fSFrançois Tigeot } 6455718399fSFrançois Tigeot 6465718399fSFrançois Tigeot } 6475718399fSFrançois Tigeot pool->fill_lock = false; 6485718399fSFrançois Tigeot } 6495718399fSFrançois Tigeot 6505718399fSFrançois Tigeot /** 6515718399fSFrançois Tigeot * Cut 'count' number of pages from the pool and put them on the return list. 6525718399fSFrançois Tigeot * 6535718399fSFrançois Tigeot * @return count of pages still required to fulfill the request. 6545718399fSFrançois Tigeot */ 6555718399fSFrançois Tigeot static unsigned ttm_page_pool_get_pages(struct ttm_page_pool *pool, 6565718399fSFrançois Tigeot struct pglist *pages, 6575718399fSFrançois Tigeot int ttm_flags, 6585718399fSFrançois Tigeot enum ttm_caching_state cstate, 6595718399fSFrançois Tigeot unsigned count) 6605718399fSFrançois Tigeot { 6616af927c2SFrançois Tigeot unsigned long irq_flags; 6625718399fSFrançois Tigeot vm_page_t p; 6635718399fSFrançois Tigeot unsigned i; 6645718399fSFrançois Tigeot 6656af927c2SFrançois Tigeot spin_lock_irqsave(&pool->lock, irq_flags); 6666af927c2SFrançois Tigeot ttm_page_pool_fill_locked(pool, ttm_flags, cstate, count, &irq_flags); 6675718399fSFrançois Tigeot 6685718399fSFrançois Tigeot if (count >= pool->npages) { 6695718399fSFrançois Tigeot /* take all pages from the pool */ 6705718399fSFrançois Tigeot TAILQ_CONCAT(pages, &pool->list, pageq); 6715718399fSFrançois Tigeot count -= pool->npages; 6725718399fSFrançois Tigeot pool->npages = 0; 6735718399fSFrançois Tigeot goto out; 6745718399fSFrançois Tigeot } 6755718399fSFrançois Tigeot for (i = 0; i < count; i++) { 6765718399fSFrançois Tigeot p = TAILQ_FIRST(&pool->list); 6775718399fSFrançois Tigeot TAILQ_REMOVE(&pool->list, p, pageq); 6785718399fSFrançois Tigeot TAILQ_INSERT_TAIL(pages, p, pageq); 6795718399fSFrançois Tigeot } 6805718399fSFrançois Tigeot pool->npages -= count; 6815718399fSFrançois Tigeot count = 0; 6825718399fSFrançois Tigeot out: 6836af927c2SFrançois Tigeot spin_unlock_irqrestore(&pool->lock, irq_flags); 6845718399fSFrançois Tigeot return count; 6855718399fSFrançois Tigeot } 6865718399fSFrançois Tigeot 6875718399fSFrançois Tigeot /* Put all pages in pages list to correct pool to wait for reuse */ 688f0bba3d1SFrançois Tigeot static void ttm_put_pages(struct page **pages, unsigned npages, int flags, 6895718399fSFrançois Tigeot enum ttm_caching_state cstate) 6905718399fSFrançois Tigeot { 6916af927c2SFrançois Tigeot unsigned long irq_flags; 6925718399fSFrançois Tigeot struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); 6935718399fSFrançois Tigeot unsigned i; 694f0bba3d1SFrançois Tigeot struct vm_page *page; 6955718399fSFrançois Tigeot 6965718399fSFrançois Tigeot if (pool == NULL) { 6975718399fSFrançois Tigeot /* No pool for this memory type so free the pages */ 6985718399fSFrançois Tigeot for (i = 0; i < npages; i++) { 6995718399fSFrançois Tigeot if (pages[i]) { 700e5c1d8f1SFrançois Tigeot #if 0 701e5c1d8f1SFrançois Tigeot if (page_count(pages[i]) != 1) 702e5c1d8f1SFrançois Tigeot pr_err("Erroneous page count. Leaking pages.\n"); 703e5c1d8f1SFrançois Tigeot #endif 704e5c1d8f1SFrançois Tigeot __free_page(pages[i]); 7055718399fSFrançois Tigeot pages[i] = NULL; 7065718399fSFrançois Tigeot } 7075718399fSFrançois Tigeot } 7085718399fSFrançois Tigeot return; 7095718399fSFrançois Tigeot } 7105718399fSFrançois Tigeot 7116af927c2SFrançois Tigeot spin_lock_irqsave(&pool->lock, irq_flags); 7125718399fSFrançois Tigeot for (i = 0; i < npages; i++) { 7135718399fSFrançois Tigeot if (pages[i]) { 714f0bba3d1SFrançois Tigeot page = (struct vm_page *)pages[i]; 715f0bba3d1SFrançois Tigeot TAILQ_INSERT_TAIL(&pool->list, page, pageq); 7165718399fSFrançois Tigeot pages[i] = NULL; 7175718399fSFrançois Tigeot pool->npages++; 7185718399fSFrançois Tigeot } 7195718399fSFrançois Tigeot } 7205718399fSFrançois Tigeot /* Check that we don't go over the pool limit */ 7215718399fSFrançois Tigeot npages = 0; 7225718399fSFrançois Tigeot if (pool->npages > _manager->options.max_size) { 7235718399fSFrançois Tigeot npages = pool->npages - _manager->options.max_size; 7245718399fSFrançois Tigeot /* free at least NUM_PAGES_TO_ALLOC number of pages 7255718399fSFrançois Tigeot * to reduce calls to set_memory_wb */ 7265718399fSFrançois Tigeot if (npages < NUM_PAGES_TO_ALLOC) 7275718399fSFrançois Tigeot npages = NUM_PAGES_TO_ALLOC; 7285718399fSFrançois Tigeot } 7296af927c2SFrançois Tigeot spin_unlock_irqrestore(&pool->lock, irq_flags); 7305718399fSFrançois Tigeot if (npages) 7317dcf36dcSFrançois Tigeot ttm_page_pool_free(pool, npages, false); 7325718399fSFrançois Tigeot } 7335718399fSFrançois Tigeot 7345718399fSFrançois Tigeot /* 7355718399fSFrançois Tigeot * On success pages list will hold count number of correctly 7365718399fSFrançois Tigeot * cached pages. 7375718399fSFrançois Tigeot */ 738f0bba3d1SFrançois Tigeot static int ttm_get_pages(struct page **pages, unsigned npages, int flags, 7395718399fSFrançois Tigeot enum ttm_caching_state cstate) 7405718399fSFrançois Tigeot { 7415718399fSFrançois Tigeot struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); 7425718399fSFrançois Tigeot struct pglist plist; 743f0bba3d1SFrançois Tigeot struct vm_page *p = NULL; 7446af927c2SFrançois Tigeot gfp_t gfp_flags = GFP_USER; 7455718399fSFrançois Tigeot unsigned count; 7465718399fSFrançois Tigeot int r; 7475718399fSFrançois Tigeot 7486af927c2SFrançois Tigeot /* set zero flag for page allocation if required */ 7496af927c2SFrançois Tigeot if (flags & TTM_PAGE_FLAG_ZERO_ALLOC) 7506af927c2SFrançois Tigeot gfp_flags |= __GFP_ZERO; 7515718399fSFrançois Tigeot 7525718399fSFrançois Tigeot /* No pool for cached pages */ 7535718399fSFrançois Tigeot if (pool == NULL) { 7546af927c2SFrançois Tigeot if (flags & TTM_PAGE_FLAG_DMA32) 7556af927c2SFrançois Tigeot gfp_flags |= GFP_DMA32; 7566af927c2SFrançois Tigeot else 7576af927c2SFrançois Tigeot gfp_flags |= GFP_HIGHUSER; 7586af927c2SFrançois Tigeot 7595718399fSFrançois Tigeot for (r = 0; r < npages; ++r) { 7606af927c2SFrançois Tigeot p = (struct vm_page *)alloc_page(gfp_flags); 7615718399fSFrançois Tigeot if (!p) { 7626af927c2SFrançois Tigeot 7630bece63dSImre Vadasz pr_err("Unable to allocate page\n"); 7645718399fSFrançois Tigeot return -ENOMEM; 7655718399fSFrançois Tigeot } 766f0bba3d1SFrançois Tigeot pages[r] = (struct page *)p; 7675718399fSFrançois Tigeot } 7685718399fSFrançois Tigeot return 0; 7695718399fSFrançois Tigeot } 7705718399fSFrançois Tigeot 7715718399fSFrançois Tigeot /* combine zero flag to pool flags */ 7726af927c2SFrançois Tigeot gfp_flags |= pool->gfp_flags; 7735718399fSFrançois Tigeot 7745718399fSFrançois Tigeot /* First we take pages from the pool */ 7755718399fSFrançois Tigeot TAILQ_INIT(&plist); 7765718399fSFrançois Tigeot npages = ttm_page_pool_get_pages(pool, &plist, flags, cstate, npages); 7775718399fSFrançois Tigeot count = 0; 7785718399fSFrançois Tigeot TAILQ_FOREACH(p, &plist, pageq) { 779f0bba3d1SFrançois Tigeot pages[count++] = (struct page *)p; 7805718399fSFrançois Tigeot } 7815718399fSFrançois Tigeot 7825718399fSFrançois Tigeot /* clear the pages coming from the pool if requested */ 7835718399fSFrançois Tigeot if (flags & TTM_PAGE_FLAG_ZERO_ALLOC) { 7845718399fSFrançois Tigeot TAILQ_FOREACH(p, &plist, pageq) { 7855718399fSFrançois Tigeot pmap_zero_page(VM_PAGE_TO_PHYS(p)); 7865718399fSFrançois Tigeot } 7875718399fSFrançois Tigeot } 7885718399fSFrançois Tigeot 7895718399fSFrançois Tigeot /* If pool didn't have enough pages allocate new one. */ 7905718399fSFrançois Tigeot if (npages > 0) { 7915718399fSFrançois Tigeot /* ttm_alloc_new_pages doesn't reference pool so we can run 7925718399fSFrançois Tigeot * multiple requests in parallel. 7935718399fSFrançois Tigeot **/ 7945718399fSFrançois Tigeot TAILQ_INIT(&plist); 7956af927c2SFrançois Tigeot r = ttm_alloc_new_pages(&plist, gfp_flags, flags, cstate, npages); 7965718399fSFrançois Tigeot TAILQ_FOREACH(p, &plist, pageq) { 797f0bba3d1SFrançois Tigeot pages[count++] = (struct page *)p; 7985718399fSFrançois Tigeot } 7995718399fSFrançois Tigeot if (r) { 8005718399fSFrançois Tigeot /* If there is any pages in the list put them back to 8015718399fSFrançois Tigeot * the pool. */ 8020bece63dSImre Vadasz pr_err("Failed to allocate extra pages for large request\n"); 8035718399fSFrançois Tigeot ttm_put_pages(pages, count, flags, cstate); 8045718399fSFrançois Tigeot return r; 8055718399fSFrançois Tigeot } 8065718399fSFrançois Tigeot } 8075718399fSFrançois Tigeot 8085718399fSFrançois Tigeot return 0; 8095718399fSFrançois Tigeot } 8105718399fSFrançois Tigeot 8111cfef1a5SFrançois Tigeot static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, gfp_t flags, 8125718399fSFrançois Tigeot char *name) 8135718399fSFrançois Tigeot { 8145718399fSFrançois Tigeot lockinit(&pool->lock, "ttmpool", 0, LK_CANRECURSE); 8155718399fSFrançois Tigeot pool->fill_lock = false; 8165718399fSFrançois Tigeot TAILQ_INIT(&pool->list); 8175718399fSFrançois Tigeot pool->npages = pool->nfrees = 0; 8186af927c2SFrançois Tigeot pool->gfp_flags = flags; 8195718399fSFrançois Tigeot pool->name = name; 8205718399fSFrançois Tigeot } 8215718399fSFrançois Tigeot 8225718399fSFrançois Tigeot int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages) 8235718399fSFrançois Tigeot { 8243a2096e8SFrançois Tigeot int ret; 8253a2096e8SFrançois Tigeot 8260bece63dSImre Vadasz WARN_ON(_manager); 8275718399fSFrançois Tigeot 8280bece63dSImre Vadasz pr_info("Initializing pool allocator\n"); 8295718399fSFrançois Tigeot 830175896dfSzrj _manager = kzalloc(sizeof(*_manager), GFP_KERNEL); 8315718399fSFrançois Tigeot 8326af927c2SFrançois Tigeot ttm_page_pool_init_locked(&_manager->wc_pool, GFP_HIGHUSER, "wc"); 8336af927c2SFrançois Tigeot 8346af927c2SFrançois Tigeot ttm_page_pool_init_locked(&_manager->uc_pool, GFP_HIGHUSER, "uc"); 8356af927c2SFrançois Tigeot 8365718399fSFrançois Tigeot ttm_page_pool_init_locked(&_manager->wc_pool_dma32, 8376af927c2SFrançois Tigeot GFP_USER | GFP_DMA32, "wc dma"); 8386af927c2SFrançois Tigeot 8395718399fSFrançois Tigeot ttm_page_pool_init_locked(&_manager->uc_pool_dma32, 8406af927c2SFrançois Tigeot GFP_USER | GFP_DMA32, "uc dma"); 8415718399fSFrançois Tigeot 8425718399fSFrançois Tigeot _manager->options.max_size = max_pages; 8435718399fSFrançois Tigeot _manager->options.small = SMALL_ALLOCATION; 8445718399fSFrançois Tigeot _manager->options.alloc_size = NUM_PAGES_TO_ALLOC; 8455718399fSFrançois Tigeot 8463a2096e8SFrançois Tigeot ret = kobject_init_and_add(&_manager->kobj, &ttm_pool_kobj_type, 8473a2096e8SFrançois Tigeot &glob->kobj, "pool"); 8483a2096e8SFrançois Tigeot if (unlikely(ret != 0)) { 8493a2096e8SFrançois Tigeot kobject_put(&_manager->kobj); 8503a2096e8SFrançois Tigeot _manager = NULL; 8513a2096e8SFrançois Tigeot return ret; 8523a2096e8SFrançois Tigeot } 8536af927c2SFrançois Tigeot 8545718399fSFrançois Tigeot ttm_pool_mm_shrink_init(_manager); 8555718399fSFrançois Tigeot 8565718399fSFrançois Tigeot return 0; 8575718399fSFrançois Tigeot } 8585718399fSFrançois Tigeot 8595718399fSFrançois Tigeot void ttm_page_alloc_fini(void) 8605718399fSFrançois Tigeot { 8615718399fSFrançois Tigeot int i; 8625718399fSFrançois Tigeot 8630bece63dSImre Vadasz pr_info("Finalizing pool allocator\n"); 8645718399fSFrançois Tigeot ttm_pool_mm_shrink_fini(_manager); 8655718399fSFrançois Tigeot 8667dcf36dcSFrançois Tigeot /* OK to use static buffer since global mutex is no longer used. */ 8675718399fSFrançois Tigeot for (i = 0; i < NUM_POOLS; ++i) 8687dcf36dcSFrançois Tigeot ttm_page_pool_free(&_manager->pools[i], FREE_ALL_PAGES, true); 8695718399fSFrançois Tigeot 8703a2096e8SFrançois Tigeot kobject_put(&_manager->kobj); 8715718399fSFrançois Tigeot _manager = NULL; 8725718399fSFrançois Tigeot } 8735718399fSFrançois Tigeot 8745718399fSFrançois Tigeot int ttm_pool_populate(struct ttm_tt *ttm) 8755718399fSFrançois Tigeot { 8765718399fSFrançois Tigeot struct ttm_mem_global *mem_glob = ttm->glob->mem_glob; 8775718399fSFrançois Tigeot unsigned i; 8785718399fSFrançois Tigeot int ret; 8795718399fSFrançois Tigeot 8805718399fSFrançois Tigeot if (ttm->state != tt_unpopulated) 8815718399fSFrançois Tigeot return 0; 8825718399fSFrançois Tigeot 8835718399fSFrançois Tigeot for (i = 0; i < ttm->num_pages; ++i) { 8845718399fSFrançois Tigeot ret = ttm_get_pages(&ttm->pages[i], 1, 8855718399fSFrançois Tigeot ttm->page_flags, 8865718399fSFrançois Tigeot ttm->caching_state); 8875718399fSFrançois Tigeot if (ret != 0) { 8885718399fSFrançois Tigeot ttm_pool_unpopulate(ttm); 8895718399fSFrançois Tigeot return -ENOMEM; 8905718399fSFrançois Tigeot } 8915718399fSFrançois Tigeot 8925718399fSFrançois Tigeot ret = ttm_mem_global_alloc_page(mem_glob, ttm->pages[i], 8935718399fSFrançois Tigeot false, false); 8945718399fSFrançois Tigeot if (unlikely(ret != 0)) { 8955718399fSFrançois Tigeot ttm_pool_unpopulate(ttm); 8965718399fSFrançois Tigeot return -ENOMEM; 8975718399fSFrançois Tigeot } 8985718399fSFrançois Tigeot } 8995718399fSFrançois Tigeot 9005718399fSFrançois Tigeot if (unlikely(ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) { 9015718399fSFrançois Tigeot ret = ttm_tt_swapin(ttm); 9025718399fSFrançois Tigeot if (unlikely(ret != 0)) { 9035718399fSFrançois Tigeot ttm_pool_unpopulate(ttm); 9045718399fSFrançois Tigeot return ret; 9055718399fSFrançois Tigeot } 9065718399fSFrançois Tigeot } 9075718399fSFrançois Tigeot 9085718399fSFrançois Tigeot ttm->state = tt_unbound; 9095718399fSFrançois Tigeot return 0; 9105718399fSFrançois Tigeot } 9113a2096e8SFrançois Tigeot EXPORT_SYMBOL(ttm_pool_populate); 9125718399fSFrançois Tigeot 9135718399fSFrançois Tigeot void ttm_pool_unpopulate(struct ttm_tt *ttm) 9145718399fSFrançois Tigeot { 9155718399fSFrançois Tigeot unsigned i; 9165718399fSFrançois Tigeot 9175718399fSFrançois Tigeot for (i = 0; i < ttm->num_pages; ++i) { 9185718399fSFrançois Tigeot if (ttm->pages[i]) { 9195718399fSFrançois Tigeot ttm_mem_global_free_page(ttm->glob->mem_glob, 9205718399fSFrançois Tigeot ttm->pages[i]); 9215718399fSFrançois Tigeot ttm_put_pages(&ttm->pages[i], 1, 9225718399fSFrançois Tigeot ttm->page_flags, 9235718399fSFrançois Tigeot ttm->caching_state); 9245718399fSFrançois Tigeot } 9255718399fSFrançois Tigeot } 9265718399fSFrançois Tigeot ttm->state = tt_unpopulated; 9275718399fSFrançois Tigeot } 9286af927c2SFrançois Tigeot EXPORT_SYMBOL(ttm_pool_unpopulate); 9295718399fSFrançois Tigeot 9305718399fSFrançois Tigeot #if 0 9315718399fSFrançois Tigeot int ttm_page_alloc_debugfs(struct seq_file *m, void *data) 9325718399fSFrançois Tigeot { 9335718399fSFrançois Tigeot struct ttm_page_pool *p; 9345718399fSFrançois Tigeot unsigned i; 9355718399fSFrançois Tigeot char *h[] = {"pool", "refills", "pages freed", "size"}; 9365718399fSFrançois Tigeot if (!_manager) { 9375718399fSFrançois Tigeot seq_printf(m, "No pool allocator running.\n"); 9385718399fSFrançois Tigeot return 0; 9395718399fSFrançois Tigeot } 9405718399fSFrançois Tigeot seq_printf(m, "%6s %12s %13s %8s\n", 9415718399fSFrançois Tigeot h[0], h[1], h[2], h[3]); 9425718399fSFrançois Tigeot for (i = 0; i < NUM_POOLS; ++i) { 9435718399fSFrançois Tigeot p = &_manager->pools[i]; 9445718399fSFrançois Tigeot 9455718399fSFrançois Tigeot seq_printf(m, "%6s %12ld %13ld %8d\n", 9465718399fSFrançois Tigeot p->name, p->nrefills, 9475718399fSFrançois Tigeot p->nfrees, p->npages); 9485718399fSFrançois Tigeot } 9495718399fSFrançois Tigeot return 0; 9505718399fSFrançois Tigeot } 9515718399fSFrançois Tigeot #endif 9523a2096e8SFrançois Tigeot EXPORT_SYMBOL(ttm_page_alloc_debugfs); 953