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

Configure Feed

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

at v4.11 162 lines 4.2 kB view raw
1/* 2 * Copyright (C) 2016 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18#include "msm_drv.h" 19#include "msm_gem.h" 20 21static bool msm_gem_shrinker_lock(struct drm_device *dev, bool *unlock) 22{ 23 switch (mutex_trylock_recursive(&dev->struct_mutex)) { 24 case MUTEX_TRYLOCK_FAILED: 25 return false; 26 27 case MUTEX_TRYLOCK_SUCCESS: 28 *unlock = true; 29 return true; 30 31 case MUTEX_TRYLOCK_RECURSIVE: 32 *unlock = false; 33 return true; 34 } 35 36 BUG(); 37} 38 39static unsigned long 40msm_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) 41{ 42 struct msm_drm_private *priv = 43 container_of(shrinker, struct msm_drm_private, shrinker); 44 struct drm_device *dev = priv->dev; 45 struct msm_gem_object *msm_obj; 46 unsigned long count = 0; 47 bool unlock; 48 49 if (!msm_gem_shrinker_lock(dev, &unlock)) 50 return 0; 51 52 list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) { 53 if (is_purgeable(msm_obj)) 54 count += msm_obj->base.size >> PAGE_SHIFT; 55 } 56 57 if (unlock) 58 mutex_unlock(&dev->struct_mutex); 59 60 return count; 61} 62 63static unsigned long 64msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) 65{ 66 struct msm_drm_private *priv = 67 container_of(shrinker, struct msm_drm_private, shrinker); 68 struct drm_device *dev = priv->dev; 69 struct msm_gem_object *msm_obj; 70 unsigned long freed = 0; 71 bool unlock; 72 73 if (!msm_gem_shrinker_lock(dev, &unlock)) 74 return SHRINK_STOP; 75 76 list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) { 77 if (freed >= sc->nr_to_scan) 78 break; 79 if (is_purgeable(msm_obj)) { 80 msm_gem_purge(&msm_obj->base); 81 freed += msm_obj->base.size >> PAGE_SHIFT; 82 } 83 } 84 85 if (unlock) 86 mutex_unlock(&dev->struct_mutex); 87 88 if (freed > 0) 89 pr_info_ratelimited("Purging %lu bytes\n", freed << PAGE_SHIFT); 90 91 return freed; 92} 93 94static int 95msm_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr) 96{ 97 struct msm_drm_private *priv = 98 container_of(nb, struct msm_drm_private, vmap_notifier); 99 struct drm_device *dev = priv->dev; 100 struct msm_gem_object *msm_obj; 101 unsigned unmapped = 0; 102 bool unlock; 103 104 if (!msm_gem_shrinker_lock(dev, &unlock)) 105 return NOTIFY_DONE; 106 107 list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) { 108 if (is_vunmapable(msm_obj)) { 109 msm_gem_vunmap(&msm_obj->base); 110 /* since we don't know any better, lets bail after a few 111 * and if necessary the shrinker will be invoked again. 112 * Seems better than unmapping *everything* 113 */ 114 if (++unmapped >= 15) 115 break; 116 } 117 } 118 119 if (unlock) 120 mutex_unlock(&dev->struct_mutex); 121 122 *(unsigned long *)ptr += unmapped; 123 124 if (unmapped > 0) 125 pr_info_ratelimited("Purging %u vmaps\n", unmapped); 126 127 return NOTIFY_DONE; 128} 129 130/** 131 * msm_gem_shrinker_init - Initialize msm shrinker 132 * @dev_priv: msm device 133 * 134 * This function registers and sets up the msm shrinker. 135 */ 136void msm_gem_shrinker_init(struct drm_device *dev) 137{ 138 struct msm_drm_private *priv = dev->dev_private; 139 priv->shrinker.count_objects = msm_gem_shrinker_count; 140 priv->shrinker.scan_objects = msm_gem_shrinker_scan; 141 priv->shrinker.seeks = DEFAULT_SEEKS; 142 WARN_ON(register_shrinker(&priv->shrinker)); 143 144 priv->vmap_notifier.notifier_call = msm_gem_shrinker_vmap; 145 WARN_ON(register_vmap_purge_notifier(&priv->vmap_notifier)); 146} 147 148/** 149 * msm_gem_shrinker_cleanup - Clean up msm shrinker 150 * @dev_priv: msm device 151 * 152 * This function unregisters the msm shrinker. 153 */ 154void msm_gem_shrinker_cleanup(struct drm_device *dev) 155{ 156 struct msm_drm_private *priv = dev->dev_private; 157 158 if (priv->shrinker.nr_deferred) { 159 WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier)); 160 unregister_shrinker(&priv->shrinker); 161 } 162}