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

drm/tegra: Implement buffer object cache

This cache is used to avoid mapping and unmapping buffer objects
unnecessarily. Mappings are cached per client and stay hot until
the buffer object is destroyed.

Signed-off-by: Thierry Reding <treding@nvidia.com>

+141 -17
+11 -3
drivers/gpu/drm/tegra/gem.c
··· 67 67 if (!map) 68 68 return ERR_PTR(-ENOMEM); 69 69 70 + kref_init(&map->ref); 70 71 map->bo = host1x_bo_get(bo); 71 72 map->direction = direction; 72 73 map->dev = dev; ··· 158 157 159 158 static void tegra_bo_unpin(struct host1x_bo_mapping *map) 160 159 { 161 - if (!map) 162 - return; 163 - 164 160 if (map->attach) { 165 161 dma_buf_unmap_attachment(map->attach, map->sgt, map->direction); 166 162 dma_buf_detach(map->attach->dmabuf, map->attach); ··· 491 493 void tegra_bo_free_object(struct drm_gem_object *gem) 492 494 { 493 495 struct tegra_drm *tegra = gem->dev->dev_private; 496 + struct host1x_bo_mapping *mapping, *tmp; 494 497 struct tegra_bo *bo = to_tegra_bo(gem); 498 + 499 + /* remove all mappings of this buffer object from any caches */ 500 + list_for_each_entry_safe(mapping, tmp, &bo->base.mappings, list) { 501 + if (mapping->cache) 502 + host1x_bo_unpin(mapping); 503 + else 504 + dev_err(gem->dev->dev, "mapping %p stale for device %s\n", mapping, 505 + dev_name(mapping->dev)); 506 + } 495 507 496 508 if (tegra->domain) 497 509 tegra_bo_iommu_unmap(tegra, bo);
+1 -1
drivers/gpu/drm/tegra/plane.c
··· 145 145 struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 146 146 struct host1x_bo_mapping *map; 147 147 148 - map = host1x_bo_pin(dc->dev, &bo->base, DMA_TO_DEVICE); 148 + map = host1x_bo_pin(dc->dev, &bo->base, DMA_TO_DEVICE, &dc->client.cache); 149 149 if (IS_ERR(map)) { 150 150 err = PTR_ERR(map); 151 151 goto unpin;
+1
drivers/gpu/drm/tegra/submit.c
··· 75 75 if (!map) 76 76 return ERR_PTR(-ENOMEM); 77 77 78 + kref_init(&map->ref); 78 79 map->bo = host1x_bo_get(bo); 79 80 map->direction = direction; 80 81 map->dev = dev;
+1 -1
drivers/gpu/drm/tegra/uapi.c
··· 201 201 goto put_gem; 202 202 } 203 203 204 - mapping->map = host1x_bo_pin(context->client->base.dev, mapping->bo, direction); 204 + mapping->map = host1x_bo_pin(context->client->base.dev, mapping->bo, direction, NULL); 205 205 if (IS_ERR(mapping->map)) { 206 206 err = PTR_ERR(mapping->map); 207 207 goto put_gem;
+78
drivers/gpu/host1x/bus.c
··· 742 742 */ 743 743 void __host1x_client_init(struct host1x_client *client, struct lock_class_key *key) 744 744 { 745 + host1x_bo_cache_init(&client->cache); 745 746 INIT_LIST_HEAD(&client->list); 746 747 __mutex_init(&client->lock, "host1x client lock", key); 747 748 client->usecount = 0; ··· 831 830 832 831 mutex_unlock(&clients_lock); 833 832 833 + host1x_bo_cache_destroy(&client->cache); 834 + 834 835 return 0; 835 836 } 836 837 EXPORT_SYMBOL(host1x_client_unregister); ··· 907 904 return err; 908 905 } 909 906 EXPORT_SYMBOL(host1x_client_resume); 907 + 908 + struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo, 909 + enum dma_data_direction dir, 910 + struct host1x_bo_cache *cache) 911 + { 912 + struct host1x_bo_mapping *mapping; 913 + 914 + if (cache) { 915 + mutex_lock(&cache->lock); 916 + 917 + list_for_each_entry(mapping, &cache->mappings, entry) { 918 + if (mapping->bo == bo && mapping->direction == dir) { 919 + kref_get(&mapping->ref); 920 + goto unlock; 921 + } 922 + } 923 + } 924 + 925 + mapping = bo->ops->pin(dev, bo, dir); 926 + if (IS_ERR(mapping)) 927 + goto unlock; 928 + 929 + spin_lock(&mapping->bo->lock); 930 + list_add_tail(&mapping->list, &bo->mappings); 931 + spin_unlock(&mapping->bo->lock); 932 + 933 + if (cache) { 934 + INIT_LIST_HEAD(&mapping->entry); 935 + mapping->cache = cache; 936 + 937 + list_add_tail(&mapping->entry, &cache->mappings); 938 + 939 + /* bump reference count to track the copy in the cache */ 940 + kref_get(&mapping->ref); 941 + } 942 + 943 + unlock: 944 + if (cache) 945 + mutex_unlock(&cache->lock); 946 + 947 + return mapping; 948 + } 949 + EXPORT_SYMBOL(host1x_bo_pin); 950 + 951 + static void __host1x_bo_unpin(struct kref *ref) 952 + { 953 + struct host1x_bo_mapping *mapping = to_host1x_bo_mapping(ref); 954 + 955 + /* 956 + * When the last reference of the mapping goes away, make sure to remove the mapping from 957 + * the cache. 958 + */ 959 + if (mapping->cache) 960 + list_del(&mapping->entry); 961 + 962 + spin_lock(&mapping->bo->lock); 963 + list_del(&mapping->list); 964 + spin_unlock(&mapping->bo->lock); 965 + 966 + mapping->bo->ops->unpin(mapping); 967 + } 968 + 969 + void host1x_bo_unpin(struct host1x_bo_mapping *mapping) 970 + { 971 + struct host1x_bo_cache *cache = mapping->cache; 972 + 973 + if (cache) 974 + mutex_lock(&cache->lock); 975 + 976 + kref_put(&mapping->ref, __host1x_bo_unpin); 977 + 978 + if (cache) 979 + mutex_unlock(&cache->lock); 980 + } 981 + EXPORT_SYMBOL(host1x_bo_unpin);
+2
drivers/gpu/host1x/dev.c
··· 386 386 if (syncpt_irq < 0) 387 387 return syncpt_irq; 388 388 389 + host1x_bo_cache_init(&host->cache); 389 390 mutex_init(&host->devices_lock); 390 391 INIT_LIST_HEAD(&host->devices); 391 392 INIT_LIST_HEAD(&host->list); ··· 513 512 reset_control_assert(host->rst); 514 513 clk_disable_unprepare(host->clk); 515 514 host1x_iommu_exit(host); 515 + host1x_bo_cache_destroy(&host->cache); 516 516 517 517 return 0; 518 518 }
+2
drivers/gpu/host1x/dev.h
··· 149 149 struct list_head list; 150 150 151 151 struct device_dma_parameters dma_parms; 152 + 153 + struct host1x_bo_cache cache; 152 154 }; 153 155 154 156 void host1x_hypervisor_writel(struct host1x *host1x, u32 r, u32 v);
+2 -2
drivers/gpu/host1x/job.c
··· 175 175 goto unpin; 176 176 } 177 177 178 - map = host1x_bo_pin(dev, bo, direction); 178 + map = host1x_bo_pin(dev, bo, direction, &client->cache); 179 179 if (IS_ERR(map)) { 180 180 err = PTR_ERR(map); 181 181 goto unpin; ··· 222 222 goto unpin; 223 223 } 224 224 225 - map = host1x_bo_pin(host->dev, g->bo, DMA_TO_DEVICE); 225 + map = host1x_bo_pin(host->dev, g->bo, DMA_TO_DEVICE, &host->cache); 226 226 if (IS_ERR(map)) { 227 227 err = PTR_ERR(map); 228 228 goto unpin;
+43 -10
include/linux/host1x.h
··· 8 8 9 9 #include <linux/device.h> 10 10 #include <linux/dma-direction.h> 11 + #include <linux/spinlock.h> 11 12 #include <linux/types.h> 12 13 13 14 enum host1x_class { ··· 24 23 struct iommu_group; 25 24 26 25 u64 host1x_get_dma_mask(struct host1x *host1x); 26 + 27 + /** 28 + * struct host1x_bo_cache - host1x buffer object cache 29 + * @mappings: list of mappings 30 + * @lock: synchronizes accesses to the list of mappings 31 + */ 32 + struct host1x_bo_cache { 33 + struct list_head mappings; 34 + struct mutex lock; 35 + }; 36 + 37 + static inline void host1x_bo_cache_init(struct host1x_bo_cache *cache) 38 + { 39 + INIT_LIST_HEAD(&cache->mappings); 40 + mutex_init(&cache->lock); 41 + } 42 + 43 + static inline void host1x_bo_cache_destroy(struct host1x_bo_cache *cache) 44 + { 45 + /* XXX warn if not empty? */ 46 + mutex_destroy(&cache->lock); 47 + } 27 48 28 49 /** 29 50 * struct host1x_client_ops - host1x client operations ··· 97 74 struct host1x_client *parent; 98 75 unsigned int usecount; 99 76 struct mutex lock; 77 + 78 + struct host1x_bo_cache cache; 100 79 }; 101 80 102 81 /* ··· 109 84 struct sg_table; 110 85 111 86 struct host1x_bo_mapping { 87 + struct kref ref; 112 88 struct dma_buf_attachment *attach; 113 89 enum dma_data_direction direction; 90 + struct list_head list; 114 91 struct host1x_bo *bo; 115 92 struct sg_table *sgt; 116 93 unsigned int chunks; 117 94 struct device *dev; 118 95 dma_addr_t phys; 119 96 size_t size; 97 + 98 + struct host1x_bo_cache *cache; 99 + struct list_head entry; 120 100 }; 101 + 102 + static inline struct host1x_bo_mapping *to_host1x_bo_mapping(struct kref *ref) 103 + { 104 + return container_of(ref, struct host1x_bo_mapping, ref); 105 + } 121 106 122 107 struct host1x_bo_ops { 123 108 struct host1x_bo *(*get)(struct host1x_bo *bo); ··· 141 106 142 107 struct host1x_bo { 143 108 const struct host1x_bo_ops *ops; 109 + struct list_head mappings; 110 + spinlock_t lock; 144 111 }; 145 112 146 113 static inline void host1x_bo_init(struct host1x_bo *bo, 147 114 const struct host1x_bo_ops *ops) 148 115 { 116 + INIT_LIST_HEAD(&bo->mappings); 117 + spin_lock_init(&bo->lock); 149 118 bo->ops = ops; 150 119 } 151 120 ··· 163 124 bo->ops->put(bo); 164 125 } 165 126 166 - static inline struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo, 167 - enum dma_data_direction dir) 168 - { 169 - return bo->ops->pin(dev, bo, dir); 170 - } 171 - 172 - static inline void host1x_bo_unpin(struct host1x_bo_mapping *map) 173 - { 174 - map->bo->ops->unpin(map); 175 - } 127 + struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo, 128 + enum dma_data_direction dir, 129 + struct host1x_bo_cache *cache); 130 + void host1x_bo_unpin(struct host1x_bo_mapping *map); 176 131 177 132 static inline void *host1x_bo_mmap(struct host1x_bo *bo) 178 133 {