From: Oak Zeng <oak.zeng@intel.com>
To: intel-xe@lists.freedesktop.org
Cc: dakr@redhat.com
Subject: [PATCH] drm/gpuvm: merge adjacent gpuva range during a map operation
Date: Wed, 18 Sep 2024 12:47:40 -0400 [thread overview]
Message-ID: <20240918164740.3955915-1-oak.zeng@intel.com> (raw)
Considder this example. Before a map operation, the gpuva ranges
in a vm looks like below:
VAs | start | range | end | object | object offset
-------------------------------------------------------------------------------------------------------------
| 0x0000000000000000 | 0x00007ffff5cd0000 | 0x00007ffff5cd0000 | 0x0000000000000000 | 0x0000000000000000
| 0x00007ffff5cf0000 | 0x00000000000c7000 | 0x00007ffff5db7000 | 0x0000000000000000 | 0x0000000000000000
Now user want to map range [0x00007ffff5cd0000 - 0x00007ffff5cf0000).
With existing codes, the range walking in __drm_gpuvm_sm_map won't
find any range, so we end up a single map operation for range
[0x00007ffff5cd0000 - 0x00007ffff5cf0000). This result in:
VAs | start | range | end | object | object offset
-------------------------------------------------------------------------------------------------------------
| 0x0000000000000000 | 0x00007ffff5cd0000 | 0x00007ffff5cd0000 | 0x0000000000000000 | 0x0000000000000000
| 0x00007ffff5cd0000 | 0x0000000000020000 | 0x00007ffff5cf0000 | 0x0000000000000000 | 0x0000000000000000
| 0x00007ffff5cf0000 | 0x00000000000c7000 | 0x00007ffff5db7000 | 0x0000000000000000 | 0x0000000000000000
The correct behavior is to merge those 3 ranges. So __drm_gpuvm_sm_map
is slightly modified to handle this corner case. The walker is changed
to find the range just before or after the mapping request, and merge
adjacent ranges using unmap and map operations. with this change, the
end result of above example is as below:
VAs | start | range | end | object | object offset
-------------------------------------------------------------------------------------------------------------
| 0x0000000000000000 | 0x00007ffff5db7000 | 0x00007ffff5db7000 | 0x0000000000000000 | 0x0000000000000000
Even though this fixes a real problem, the codes looks a little ugly.
So I welcome any better fix or suggestion.
Signed-off-by: Oak Zeng <oak.zeng@intel.com>
---
drivers/gpu/drm/drm_gpuvm.c | 62 +++++++++++++++++++++++++------------
1 file changed, 43 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c
index 4b6fcaea635e..51825c794bdc 100644
--- a/drivers/gpu/drm/drm_gpuvm.c
+++ b/drivers/gpu/drm/drm_gpuvm.c
@@ -2104,28 +2104,30 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
{
struct drm_gpuva *va, *next;
u64 req_end = req_addr + req_range;
+ u64 merged_req_addr = req_addr;
+ u64 merged_req_end = req_end;
int ret;
if (unlikely(!drm_gpuvm_range_valid(gpuvm, req_addr, req_range)))
return -EINVAL;
- drm_gpuvm_for_each_va_range_safe(va, next, gpuvm, req_addr, req_end) {
+ drm_gpuvm_for_each_va_range_safe(va, next, gpuvm, req_addr - 1, req_end + 1) {
struct drm_gem_object *obj = va->gem.obj;
u64 offset = va->gem.offset;
u64 addr = va->va.addr;
u64 range = va->va.range;
u64 end = addr + range;
- bool merge = !!va->gem.obj;
+ bool merge;
if (addr == req_addr) {
- merge &= obj == req_obj &&
+ merge = obj == req_obj &&
offset == req_offset;
if (end == req_end) {
ret = op_unmap_cb(ops, priv, va, merge);
if (ret)
return ret;
- break;
+ continue;
}
if (end < req_end) {
@@ -2162,22 +2164,33 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
};
struct drm_gpuva_op_unmap u = { .va = va };
- merge &= obj == req_obj &&
- offset + ls_range == req_offset;
+ merge = (obj && obj == req_obj &&
+ offset + ls_range == req_offset) ||
+ (!obj && !req_obj);
u.keep = merge;
if (end == req_end) {
ret = op_remap_cb(ops, priv, &p, NULL, &u);
if (ret)
return ret;
- break;
+ continue;
}
if (end < req_end) {
- ret = op_remap_cb(ops, priv, &p, NULL, &u);
- if (ret)
- return ret;
- continue;
+ if (end == req_addr) {
+ if (merge) {
+ ret = op_unmap_cb(ops, priv, va, merge);
+ if (ret)
+ return ret;
+ merged_req_addr = addr;
+ continue;
+ }
+ } else {
+ ret = op_remap_cb(ops, priv, &p, NULL, &u);
+ if (ret)
+ return ret;
+ continue;
+ }
}
if (end > req_end) {
@@ -2195,15 +2208,16 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
break;
}
} else if (addr > req_addr) {
- merge &= obj == req_obj &&
+ merge = (obj && obj == req_obj &&
offset == req_offset +
- (addr - req_addr);
+ (addr - req_addr)) ||
+ (!obj && !req_obj);
if (end == req_end) {
ret = op_unmap_cb(ops, priv, va, merge);
if (ret)
return ret;
- break;
+ continue;
}
if (end < req_end) {
@@ -2225,16 +2239,26 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
.keep = merge,
};
- ret = op_remap_cb(ops, priv, NULL, &n, &u);
- if (ret)
- return ret;
- break;
+ if (addr == req_end) {
+ if (merge) {
+ ret = op_unmap_cb(ops, priv, va, merge);
+ if (ret)
+ return ret;
+ merged_req_end = end;
+ break;
+ }
+ } else {
+ ret = op_remap_cb(ops, priv, NULL, &n, &u);
+ if (ret)
+ return ret;
+ break;
+ }
}
}
}
return op_map_cb(ops, priv,
- req_addr, req_range,
+ merged_req_addr, merged_req_end - merged_req_addr,
req_obj, req_offset);
}
--
2.26.3
next reply other threads:[~2024-09-18 16:34 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-18 16:47 Oak Zeng [this message]
2024-09-18 18:37 ` [PATCH] drm/gpuvm: merge adjacent gpuva range during a map operation Matthew Brost
2024-09-19 15:09 ` Zeng, Oak
2024-09-19 15:48 ` Matthew Brost
2024-09-19 15:56 ` Matthew Brost
2024-09-19 16:32 ` Zeng, Oak
2024-09-19 18:29 ` Matthew Brost
2024-09-23 8:22 ` Danilo Krummrich
2024-09-23 14:24 ` Zeng, Oak
2024-09-23 23:41 ` Danilo Krummrich
2024-09-24 2:00 ` Matthew Brost
2024-09-23 8:19 ` Danilo Krummrich
2024-09-18 20:02 ` ✓ CI.Patch_applied: success for " Patchwork
2024-09-18 20:03 ` ✗ CI.checkpatch: warning " Patchwork
2024-09-18 20:04 ` ✓ CI.KUnit: success " Patchwork
2024-09-18 20:16 ` ✓ CI.Build: " Patchwork
2024-09-18 20:18 ` ✓ CI.Hooks: " Patchwork
2024-09-18 20:20 ` ✓ CI.checksparse: " Patchwork
2024-09-18 20:53 ` ✗ CI.BAT: failure " Patchwork
2024-09-19 8:16 ` ✗ CI.FULL: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240918164740.3955915-1-oak.zeng@intel.com \
--to=oak.zeng@intel.com \
--cc=dakr@redhat.com \
--cc=intel-xe@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox