Branch data Line data Source code
1 : : /* 2 : : * SPDX-License-Identifier: MIT 3 : : * 4 : : * Copyright © 2014-2018 Intel Corporation 5 : : */ 6 : : 7 : : #include "gem/i915_gem_object.h" 8 : : 9 : : #include "i915_drv.h" 10 : : #include "intel_engine_pm.h" 11 : : #include "intel_engine_pool.h" 12 : : 13 : 0 : static struct intel_engine_cs *to_engine(struct intel_engine_pool *pool) 14 : : { 15 : 0 : return container_of(pool, struct intel_engine_cs, pool); 16 : : } 17 : : 18 : : static struct list_head * 19 : 0 : bucket_for_size(struct intel_engine_pool *pool, size_t sz) 20 : : { 21 : 0 : int n; 22 : : 23 : : /* 24 : : * Compute a power-of-two bucket, but throw everything greater than 25 : : * 16KiB into the same bucket: i.e. the buckets hold objects of 26 : : * (1 page, 2 pages, 4 pages, 8+ pages). 27 : : */ 28 : 0 : n = fls(sz >> PAGE_SHIFT) - 1; 29 [ # # # # ]: 0 : if (n >= ARRAY_SIZE(pool->cache_list)) 30 : 0 : n = ARRAY_SIZE(pool->cache_list) - 1; 31 : : 32 : 0 : return &pool->cache_list[n]; 33 : : } 34 : : 35 : 0 : static void node_free(struct intel_engine_pool_node *node) 36 : : { 37 : 0 : i915_gem_object_put(node->obj); 38 : 0 : i915_active_fini(&node->active); 39 : 0 : kfree(node); 40 : : } 41 : : 42 : 0 : static int pool_active(struct i915_active *ref) 43 : : { 44 : 0 : struct intel_engine_pool_node *node = 45 : 0 : container_of(ref, typeof(*node), active); 46 : 0 : struct dma_resv *resv = node->obj->base.resv; 47 : 0 : int err; 48 : : 49 [ # # ]: 0 : if (dma_resv_trylock(resv)) { 50 : 0 : dma_resv_add_excl_fence(resv, NULL); 51 : 0 : dma_resv_unlock(resv); 52 : : } 53 : : 54 : 0 : err = i915_gem_object_pin_pages(node->obj); 55 [ # # ]: 0 : if (err) 56 : : return err; 57 : : 58 : : /* Hide this pinned object from the shrinker until retired */ 59 : 0 : i915_gem_object_make_unshrinkable(node->obj); 60 : : 61 : 0 : return 0; 62 : : } 63 : : 64 : : __i915_active_call 65 : 0 : static void pool_retire(struct i915_active *ref) 66 : : { 67 : 0 : struct intel_engine_pool_node *node = 68 : 0 : container_of(ref, typeof(*node), active); 69 : 0 : struct intel_engine_pool *pool = node->pool; 70 [ # # ]: 0 : struct list_head *list = bucket_for_size(pool, node->obj->base.size); 71 : 0 : unsigned long flags; 72 : : 73 : 0 : GEM_BUG_ON(!intel_engine_pm_is_awake(to_engine(pool))); 74 : : 75 : 0 : i915_gem_object_unpin_pages(node->obj); 76 : : 77 : : /* Return this object to the shrinker pool */ 78 : 0 : i915_gem_object_make_purgeable(node->obj); 79 : : 80 : 0 : spin_lock_irqsave(&pool->lock, flags); 81 : 0 : list_add(&node->link, list); 82 : 0 : spin_unlock_irqrestore(&pool->lock, flags); 83 : 0 : } 84 : : 85 : : static struct intel_engine_pool_node * 86 : 0 : node_create(struct intel_engine_pool *pool, size_t sz) 87 : : { 88 : 0 : struct intel_engine_cs *engine = to_engine(pool); 89 : 0 : struct intel_engine_pool_node *node; 90 : 0 : struct drm_i915_gem_object *obj; 91 : : 92 : 0 : node = kmalloc(sizeof(*node), 93 : : GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); 94 [ # # ]: 0 : if (!node) 95 : : return ERR_PTR(-ENOMEM); 96 : : 97 : 0 : node->pool = pool; 98 : 0 : i915_active_init(&node->active, pool_active, pool_retire); 99 : : 100 : 0 : obj = i915_gem_object_create_internal(engine->i915, sz); 101 [ # # ]: 0 : if (IS_ERR(obj)) { 102 : 0 : i915_active_fini(&node->active); 103 : 0 : kfree(node); 104 : 0 : return ERR_CAST(obj); 105 : : } 106 : : 107 : 0 : i915_gem_object_set_readonly(obj); 108 : : 109 : 0 : node->obj = obj; 110 : 0 : return node; 111 : : } 112 : : 113 : 0 : static struct intel_engine_pool *lookup_pool(struct intel_engine_cs *engine) 114 : : { 115 : 0 : if (intel_engine_is_virtual(engine)) 116 : 0 : engine = intel_virtual_engine_get_sibling(engine, 0); 117 : : 118 : 0 : GEM_BUG_ON(!engine); 119 : 0 : return &engine->pool; 120 : : } 121 : : 122 : : struct intel_engine_pool_node * 123 : 0 : intel_engine_get_pool(struct intel_engine_cs *engine, size_t size) 124 : : { 125 [ # # ]: 0 : struct intel_engine_pool *pool = lookup_pool(engine); 126 : 0 : struct intel_engine_pool_node *node; 127 : 0 : struct list_head *list; 128 : 0 : unsigned long flags; 129 : 0 : int ret; 130 : : 131 : 0 : GEM_BUG_ON(!intel_engine_pm_is_awake(to_engine(pool))); 132 : : 133 : 0 : size = PAGE_ALIGN(size); 134 [ # # ]: 0 : list = bucket_for_size(pool, size); 135 : : 136 : 0 : spin_lock_irqsave(&pool->lock, flags); 137 [ # # ]: 0 : list_for_each_entry(node, list, link) { 138 [ # # ]: 0 : if (node->obj->base.size < size) 139 : 0 : continue; 140 : 0 : list_del(&node->link); 141 : : break; 142 : : } 143 : 0 : spin_unlock_irqrestore(&pool->lock, flags); 144 : : 145 [ # # ]: 0 : if (&node->link == list) { 146 : 0 : node = node_create(pool, size); 147 [ # # ]: 0 : if (IS_ERR(node)) 148 : : return node; 149 : : } 150 : : 151 : 0 : ret = i915_active_acquire(&node->active); 152 [ # # ]: 0 : if (ret) { 153 : 0 : node_free(node); 154 : 0 : return ERR_PTR(ret); 155 : : } 156 : : 157 : : return node; 158 : : } 159 : : 160 : 0 : void intel_engine_pool_init(struct intel_engine_pool *pool) 161 : : { 162 : 0 : int n; 163 : : 164 : 0 : spin_lock_init(&pool->lock); 165 [ # # ]: 0 : for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++) 166 : 0 : INIT_LIST_HEAD(&pool->cache_list[n]); 167 : 0 : } 168 : : 169 : 0 : void intel_engine_pool_park(struct intel_engine_pool *pool) 170 : : { 171 : 0 : int n; 172 : : 173 [ # # ]: 0 : for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++) { 174 : 0 : struct list_head *list = &pool->cache_list[n]; 175 : 0 : struct intel_engine_pool_node *node, *nn; 176 : : 177 [ # # ]: 0 : list_for_each_entry_safe(node, nn, list, link) 178 : 0 : node_free(node); 179 : : 180 : 0 : INIT_LIST_HEAD(list); 181 : : } 182 : 0 : } 183 : : 184 : 0 : void intel_engine_pool_fini(struct intel_engine_pool *pool) 185 : : { 186 : 0 : int n; 187 : : 188 : 0 : for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++) 189 : : GEM_BUG_ON(!list_empty(&pool->cache_list[n])); 190 : 0 : }