Skip to content

Commit f701b16

Browse files
committed
drm/i915/ttm: add i915_sg_from_buddy_resource
We need to be able to build an sg table from our list of buddy blocks, so that we can later plug this into our ttm backend, and replace our use of the range manager. Signed-off-by: Matthew Auld <[email protected]> Cc: Thomas Hellström <[email protected]> Reviewed-by: Thomas Hellström <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 88be9a0 commit f701b16

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

drivers/gpu/drm/i915/i915_scatterlist.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
#include "i915_scatterlist.h"
88

9+
#include "i915_buddy.h"
10+
#include "i915_ttm_buddy_manager.h"
11+
912
#include <drm/drm_mm.h>
1013

1114
#include <linux/slab.h>
@@ -104,6 +107,83 @@ struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
104107
return st;
105108
}
106109

110+
/**
111+
* i915_sg_from_buddy_resource - Create an sg_table from a struct
112+
* i915_buddy_block list
113+
* @res: The struct i915_ttm_buddy_resource.
114+
* @region_start: An offset to add to the dma addresses of the sg list.
115+
*
116+
* Create a struct sg_table, initializing it from struct i915_buddy_block list,
117+
* taking a maximum segment length into account, splitting into segments
118+
* if necessary.
119+
*
120+
* Return: A pointer to a kmalloced struct sg_table on success, negative
121+
* error code cast to an error pointer on failure.
122+
*/
123+
struct sg_table *i915_sg_from_buddy_resource(struct ttm_resource *res,
124+
u64 region_start)
125+
{
126+
struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
127+
const u64 size = res->num_pages << PAGE_SHIFT;
128+
const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE);
129+
struct i915_buddy_mm *mm = bman_res->mm;
130+
struct list_head *blocks = &bman_res->blocks;
131+
struct i915_buddy_block *block;
132+
struct scatterlist *sg;
133+
struct sg_table *st;
134+
resource_size_t prev_end;
135+
136+
GEM_BUG_ON(list_empty(blocks));
137+
138+
st = kmalloc(sizeof(*st), GFP_KERNEL);
139+
if (!st)
140+
return ERR_PTR(-ENOMEM);
141+
142+
if (sg_alloc_table(st, res->num_pages, GFP_KERNEL)) {
143+
kfree(st);
144+
return ERR_PTR(-ENOMEM);
145+
}
146+
147+
sg = st->sgl;
148+
st->nents = 0;
149+
prev_end = (resource_size_t)-1;
150+
151+
list_for_each_entry(block, blocks, link) {
152+
u64 block_size, offset;
153+
154+
block_size = min_t(u64, size, i915_buddy_block_size(mm, block));
155+
offset = i915_buddy_block_offset(block);
156+
157+
while (block_size) {
158+
u64 len;
159+
160+
if (offset != prev_end || sg->length >= max_segment) {
161+
if (st->nents)
162+
sg = __sg_next(sg);
163+
164+
sg_dma_address(sg) = region_start + offset;
165+
sg_dma_len(sg) = 0;
166+
sg->length = 0;
167+
st->nents++;
168+
}
169+
170+
len = min(block_size, max_segment - sg->length);
171+
sg->length += len;
172+
sg_dma_len(sg) += len;
173+
174+
offset += len;
175+
block_size -= len;
176+
177+
prev_end = offset;
178+
}
179+
}
180+
181+
sg_mark_end(sg);
182+
i915_sg_trim(st);
183+
184+
return st;
185+
}
186+
107187
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
108188
#include "selftests/scatterlist.c"
109189
#endif

drivers/gpu/drm/i915/i915_scatterlist.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "i915_gem.h"
1515

1616
struct drm_mm_node;
17+
struct ttm_resource;
1718

1819
/*
1920
* Optimised SGL iterator for GEM objects
@@ -145,4 +146,8 @@ bool i915_sg_trim(struct sg_table *orig_st);
145146

146147
struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node,
147148
u64 region_start);
149+
150+
struct sg_table *i915_sg_from_buddy_resource(struct ttm_resource *res,
151+
u64 region_start);
152+
148153
#endif

0 commit comments

Comments
 (0)