Skip to content

Commit 1f39b1d

Browse files
committed
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>
1 parent c6aeaf5 commit 1f39b1d

File tree

9 files changed

+141
-17
lines changed

9 files changed

+141
-17
lines changed

drivers/gpu/drm/tegra/gem.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ static struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_
6767
if (!map)
6868
return ERR_PTR(-ENOMEM);
6969

70+
kref_init(&map->ref);
7071
map->bo = host1x_bo_get(bo);
7172
map->direction = direction;
7273
map->dev = dev;
@@ -157,9 +158,6 @@ static struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_
157158

158159
static void tegra_bo_unpin(struct host1x_bo_mapping *map)
159160
{
160-
if (!map)
161-
return;
162-
163161
if (map->attach) {
164162
dma_buf_unmap_attachment(map->attach, map->sgt, map->direction);
165163
dma_buf_detach(map->attach->dmabuf, map->attach);
@@ -493,8 +491,18 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
493491
void tegra_bo_free_object(struct drm_gem_object *gem)
494492
{
495493
struct tegra_drm *tegra = gem->dev->dev_private;
494+
struct host1x_bo_mapping *mapping, *tmp;
496495
struct tegra_bo *bo = to_tegra_bo(gem);
497496

497+
/* remove all mappings of this buffer object from any caches */
498+
list_for_each_entry_safe(mapping, tmp, &bo->base.mappings, list) {
499+
if (mapping->cache)
500+
host1x_bo_unpin(mapping);
501+
else
502+
dev_err(gem->dev->dev, "mapping %p stale for device %s\n", mapping,
503+
dev_name(mapping->dev));
504+
}
505+
498506
if (tegra->domain)
499507
tegra_bo_iommu_unmap(tegra, bo);
500508

drivers/gpu/drm/tegra/plane.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state)
145145
struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
146146
struct host1x_bo_mapping *map;
147147

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);
149149
if (IS_ERR(map)) {
150150
err = PTR_ERR(map);
151151
goto unpin;

drivers/gpu/drm/tegra/submit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ gather_bo_pin(struct device *dev, struct host1x_bo *bo, enum dma_data_direction
7575
if (!map)
7676
return ERR_PTR(-ENOMEM);
7777

78+
kref_init(&map->ref);
7879
map->bo = host1x_bo_get(bo);
7980
map->direction = direction;
8081
map->dev = dev;

drivers/gpu/drm/tegra/uapi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data, struct drm_f
201201
goto put_gem;
202202
}
203203

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);
205205
if (IS_ERR(mapping->map)) {
206206
err = PTR_ERR(mapping->map);
207207
goto put_gem;

drivers/gpu/host1x/bus.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,7 @@ EXPORT_SYMBOL(host1x_driver_unregister);
742742
*/
743743
void __host1x_client_init(struct host1x_client *client, struct lock_class_key *key)
744744
{
745+
host1x_bo_cache_init(&client->cache);
745746
INIT_LIST_HEAD(&client->list);
746747
__mutex_init(&client->lock, "host1x client lock", key);
747748
client->usecount = 0;
@@ -830,6 +831,8 @@ int host1x_client_unregister(struct host1x_client *client)
830831

831832
mutex_unlock(&clients_lock);
832833

834+
host1x_bo_cache_destroy(&client->cache);
835+
833836
return 0;
834837
}
835838
EXPORT_SYMBOL(host1x_client_unregister);
@@ -904,3 +907,78 @@ int host1x_client_resume(struct host1x_client *client)
904907
return err;
905908
}
906909
EXPORT_SYMBOL(host1x_client_resume);
910+
911+
struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo,
912+
enum dma_data_direction dir,
913+
struct host1x_bo_cache *cache)
914+
{
915+
struct host1x_bo_mapping *mapping;
916+
917+
if (cache) {
918+
mutex_lock(&cache->lock);
919+
920+
list_for_each_entry(mapping, &cache->mappings, entry) {
921+
if (mapping->bo == bo && mapping->direction == dir) {
922+
kref_get(&mapping->ref);
923+
goto unlock;
924+
}
925+
}
926+
}
927+
928+
mapping = bo->ops->pin(dev, bo, dir);
929+
if (IS_ERR(mapping))
930+
goto unlock;
931+
932+
spin_lock(&mapping->bo->lock);
933+
list_add_tail(&mapping->list, &bo->mappings);
934+
spin_unlock(&mapping->bo->lock);
935+
936+
if (cache) {
937+
INIT_LIST_HEAD(&mapping->entry);
938+
mapping->cache = cache;
939+
940+
list_add_tail(&mapping->entry, &cache->mappings);
941+
942+
/* bump reference count to track the copy in the cache */
943+
kref_get(&mapping->ref);
944+
}
945+
946+
unlock:
947+
if (cache)
948+
mutex_unlock(&cache->lock);
949+
950+
return mapping;
951+
}
952+
EXPORT_SYMBOL(host1x_bo_pin);
953+
954+
static void __host1x_bo_unpin(struct kref *ref)
955+
{
956+
struct host1x_bo_mapping *mapping = to_host1x_bo_mapping(ref);
957+
958+
/*
959+
* When the last reference of the mapping goes away, make sure to remove the mapping from
960+
* the cache.
961+
*/
962+
if (mapping->cache)
963+
list_del(&mapping->entry);
964+
965+
spin_lock(&mapping->bo->lock);
966+
list_del(&mapping->list);
967+
spin_unlock(&mapping->bo->lock);
968+
969+
mapping->bo->ops->unpin(mapping);
970+
}
971+
972+
void host1x_bo_unpin(struct host1x_bo_mapping *mapping)
973+
{
974+
struct host1x_bo_cache *cache = mapping->cache;
975+
976+
if (cache)
977+
mutex_lock(&cache->lock);
978+
979+
kref_put(&mapping->ref, __host1x_bo_unpin);
980+
981+
if (cache)
982+
mutex_unlock(&cache->lock);
983+
}
984+
EXPORT_SYMBOL(host1x_bo_unpin);

drivers/gpu/host1x/dev.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ static int host1x_probe(struct platform_device *pdev)
386386
if (syncpt_irq < 0)
387387
return syncpt_irq;
388388

389+
host1x_bo_cache_init(&host->cache);
389390
mutex_init(&host->devices_lock);
390391
INIT_LIST_HEAD(&host->devices);
391392
INIT_LIST_HEAD(&host->list);
@@ -512,6 +513,7 @@ static int host1x_remove(struct platform_device *pdev)
512513
reset_control_assert(host->rst);
513514
clk_disable_unprepare(host->clk);
514515
host1x_iommu_exit(host);
516+
host1x_bo_cache_destroy(&host->cache);
515517

516518
return 0;
517519
}

drivers/gpu/host1x/dev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ struct host1x {
149149
struct list_head list;
150150

151151
struct device_dma_parameters dma_parms;
152+
153+
struct host1x_bo_cache cache;
152154
};
153155

154156
void host1x_hypervisor_writel(struct host1x *host1x, u32 r, u32 v);

drivers/gpu/host1x/job.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
175175
goto unpin;
176176
}
177177

178-
map = host1x_bo_pin(dev, bo, direction);
178+
map = host1x_bo_pin(dev, bo, direction, &client->cache);
179179
if (IS_ERR(map)) {
180180
err = PTR_ERR(map);
181181
goto unpin;
@@ -222,7 +222,7 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
222222
goto unpin;
223223
}
224224

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);
226226
if (IS_ERR(map)) {
227227
err = PTR_ERR(map);
228228
goto unpin;

include/linux/host1x.h

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/device.h>
1010
#include <linux/dma-direction.h>
11+
#include <linux/spinlock.h>
1112
#include <linux/types.h>
1213

1314
enum host1x_class {
@@ -24,6 +25,28 @@ struct iommu_group;
2425

2526
u64 host1x_get_dma_mask(struct host1x *host1x);
2627

28+
/**
29+
* struct host1x_bo_cache - host1x buffer object cache
30+
* @mappings: list of mappings
31+
* @lock: synchronizes accesses to the list of mappings
32+
*/
33+
struct host1x_bo_cache {
34+
struct list_head mappings;
35+
struct mutex lock;
36+
};
37+
38+
static inline void host1x_bo_cache_init(struct host1x_bo_cache *cache)
39+
{
40+
INIT_LIST_HEAD(&cache->mappings);
41+
mutex_init(&cache->lock);
42+
}
43+
44+
static inline void host1x_bo_cache_destroy(struct host1x_bo_cache *cache)
45+
{
46+
/* XXX warn if not empty? */
47+
mutex_destroy(&cache->lock);
48+
}
49+
2750
/**
2851
* struct host1x_client_ops - host1x client operations
2952
* @early_init: host1x client early initialization code
@@ -74,6 +97,8 @@ struct host1x_client {
7497
struct host1x_client *parent;
7598
unsigned int usecount;
7699
struct mutex lock;
100+
101+
struct host1x_bo_cache cache;
77102
};
78103

79104
/*
@@ -84,16 +109,26 @@ struct host1x_bo;
84109
struct sg_table;
85110

86111
struct host1x_bo_mapping {
112+
struct kref ref;
87113
struct dma_buf_attachment *attach;
88114
enum dma_data_direction direction;
115+
struct list_head list;
89116
struct host1x_bo *bo;
90117
struct sg_table *sgt;
91118
unsigned int chunks;
92119
struct device *dev;
93120
dma_addr_t phys;
94121
size_t size;
122+
123+
struct host1x_bo_cache *cache;
124+
struct list_head entry;
95125
};
96126

127+
static inline struct host1x_bo_mapping *to_host1x_bo_mapping(struct kref *ref)
128+
{
129+
return container_of(ref, struct host1x_bo_mapping, ref);
130+
}
131+
97132
struct host1x_bo_ops {
98133
struct host1x_bo *(*get)(struct host1x_bo *bo);
99134
void (*put)(struct host1x_bo *bo);
@@ -106,11 +141,15 @@ struct host1x_bo_ops {
106141

107142
struct host1x_bo {
108143
const struct host1x_bo_ops *ops;
144+
struct list_head mappings;
145+
spinlock_t lock;
109146
};
110147

111148
static inline void host1x_bo_init(struct host1x_bo *bo,
112149
const struct host1x_bo_ops *ops)
113150
{
151+
INIT_LIST_HEAD(&bo->mappings);
152+
spin_lock_init(&bo->lock);
114153
bo->ops = ops;
115154
}
116155

@@ -124,16 +163,10 @@ static inline void host1x_bo_put(struct host1x_bo *bo)
124163
bo->ops->put(bo);
125164
}
126165

127-
static inline struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo,
128-
enum dma_data_direction dir)
129-
{
130-
return bo->ops->pin(dev, bo, dir);
131-
}
132-
133-
static inline void host1x_bo_unpin(struct host1x_bo_mapping *map)
134-
{
135-
map->bo->ops->unpin(map);
136-
}
166+
struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo,
167+
enum dma_data_direction dir,
168+
struct host1x_bo_cache *cache);
169+
void host1x_bo_unpin(struct host1x_bo_mapping *map);
137170

138171
static inline void *host1x_bo_mmap(struct host1x_bo *bo)
139172
{

0 commit comments

Comments
 (0)