^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/dma-buf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #undef CONFIG_DMABUF_CACHE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/dma-buf-cache.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct dma_buf_cache_list {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct list_head head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) struct dma_buf_cache {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct dma_buf_attachment *attach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) enum dma_data_direction direction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct sg_table *sg_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int dma_buf_cache_destructor(struct dma_buf *dmabuf, void *dtor_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct dma_buf_cache_list *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct dma_buf_cache *cache, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) data = dmabuf->dtor_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) list_for_each_entry_safe(cache, tmp, &data->head, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (!IS_ERR_OR_NULL(cache->sg_table))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) dma_buf_unmap_attachment(cache->attach,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) cache->sg_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) cache->direction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) dma_buf_detach(dmabuf, cache->attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) list_del(&cache->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) kfree(cache);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static struct dma_buf_cache *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) dma_buf_cache_get_cache(struct dma_buf_attachment *attach)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct dma_buf_cache_list *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct dma_buf_cache *cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct dma_buf *dmabuf = attach->dmabuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (dmabuf->dtor != dma_buf_cache_destructor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) data = dmabuf->dtor_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) list_for_each_entry(cache, &data->head, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (cache->attach == attach) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) void dma_buf_cache_detach(struct dma_buf *dmabuf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct dma_buf_attachment *attach)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct dma_buf_cache *cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) cache = dma_buf_cache_get_cache(attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (!cache)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) dma_buf_detach(dmabuf, attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) EXPORT_SYMBOL(dma_buf_cache_detach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct dma_buf_attachment *dma_buf_cache_attach(struct dma_buf *dmabuf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct dma_buf_attachment *attach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct dma_buf_cache_list *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct dma_buf_cache *cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (!dmabuf->dtor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) data = kzalloc(sizeof(*data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) mutex_init(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) INIT_LIST_HEAD(&data->head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) dma_buf_set_destructor(dmabuf, dma_buf_cache_destructor, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (dmabuf->dtor && dmabuf->dtor != dma_buf_cache_destructor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return dma_buf_attach(dmabuf, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) data = dmabuf->dtor_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) list_for_each_entry(cache, &data->head, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (cache->attach->dev == dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /* Already attached */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return cache->attach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) cache = kzalloc(sizeof(*cache), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (!cache)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* Cache attachment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) attach = dma_buf_attach(dmabuf, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (IS_ERR_OR_NULL(attach)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) kfree(cache);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return attach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) cache->attach = attach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) list_add(&cache->list, &data->head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return cache->attach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) EXPORT_SYMBOL(dma_buf_cache_attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) void dma_buf_cache_unmap_attachment(struct dma_buf_attachment *attach,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) struct sg_table *sg_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) enum dma_data_direction direction)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct dma_buf_cache *cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) cache = dma_buf_cache_get_cache(attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (!cache)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) dma_buf_unmap_attachment(attach, sg_table, direction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) EXPORT_SYMBOL(dma_buf_cache_unmap_attachment);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct sg_table *dma_buf_cache_map_attachment(struct dma_buf_attachment *attach,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) enum dma_data_direction direction)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct dma_buf_cache *cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) cache = dma_buf_cache_get_cache(attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (!cache)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return dma_buf_map_attachment(attach, direction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (cache->sg_table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* Already mapped */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (cache->direction == direction)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return cache->sg_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* Different directions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) dma_buf_unmap_attachment(attach, cache->sg_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) cache->direction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* Cache map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) cache->sg_table = dma_buf_map_attachment(attach, direction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) cache->direction = direction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return cache->sg_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) EXPORT_SYMBOL(dma_buf_cache_map_attachment);