Skip to content

Commit f180bf1

Browse files
Jérôme GlisseBen Skeggs
authored andcommitted
drm/nouveau/svm: new ioctl to migrate process memory to GPU memory
This add an ioctl to migrate a range of process address space to the device memory. On platform without cache coherent bus (x86, ARM, ...) this means that CPU can not access that range directly, instead CPU will fault which will migrate the memory back to system memory. This is behind a staging flag so that we can evolve the API. Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
1 parent 5be73b6 commit f180bf1

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

drivers/gpu/drm/nouveau/nouveau_drm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,7 @@ nouveau_ioctls[] = {
10431043
DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_AUTH|DRM_RENDER_ALLOW),
10441044
DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_AUTH|DRM_RENDER_ALLOW),
10451045
DRM_IOCTL_DEF_DRV(NOUVEAU_SVM_INIT, nouveau_svmm_init, DRM_AUTH|DRM_RENDER_ALLOW),
1046+
DRM_IOCTL_DEF_DRV(NOUVEAU_SVM_BIND, nouveau_svmm_bind, DRM_AUTH|DRM_RENDER_ALLOW),
10461047
DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH|DRM_RENDER_ALLOW),
10471048
DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH|DRM_RENDER_ALLOW),
10481049
DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW),

drivers/gpu/drm/nouveau/nouveau_svm.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "nouveau_svm.h"
2323
#include "nouveau_drv.h"
2424
#include "nouveau_chan.h"
25+
#include "nouveau_dmem.h"
2526

2627
#include <nvif/notify.h>
2728
#include <nvif/object.h>
@@ -104,6 +105,101 @@ struct nouveau_svmm {
104105
#define SVMM_ERR(s,f,a...) \
105106
NV_WARN((s)->vmm->cli->drm, "svm-%p: "f"\n", (s), ##a)
106107

108+
int
109+
nouveau_svmm_bind(struct drm_device *dev, void *data,
110+
struct drm_file *file_priv)
111+
{
112+
struct nouveau_cli *cli = nouveau_cli(file_priv);
113+
struct drm_nouveau_svm_bind *args = data;
114+
unsigned target, cmd, priority;
115+
unsigned long addr, end, size;
116+
struct mm_struct *mm;
117+
118+
args->va_start &= PAGE_MASK;
119+
args->va_end &= PAGE_MASK;
120+
121+
/* Sanity check arguments */
122+
if (args->reserved0 || args->reserved1)
123+
return -EINVAL;
124+
if (args->header & (~NOUVEAU_SVM_BIND_VALID_MASK))
125+
return -EINVAL;
126+
if (args->va_start >= args->va_end)
127+
return -EINVAL;
128+
if (!args->npages)
129+
return -EINVAL;
130+
131+
cmd = args->header >> NOUVEAU_SVM_BIND_COMMAND_SHIFT;
132+
cmd &= NOUVEAU_SVM_BIND_COMMAND_MASK;
133+
switch (cmd) {
134+
case NOUVEAU_SVM_BIND_COMMAND__MIGRATE:
135+
break;
136+
default:
137+
return -EINVAL;
138+
}
139+
140+
priority = args->header >> NOUVEAU_SVM_BIND_PRIORITY_SHIFT;
141+
priority &= NOUVEAU_SVM_BIND_PRIORITY_MASK;
142+
143+
/* FIXME support CPU target ie all target value < GPU_VRAM */
144+
target = args->header >> NOUVEAU_SVM_BIND_TARGET_SHIFT;
145+
target &= NOUVEAU_SVM_BIND_TARGET_MASK;
146+
switch (target) {
147+
case NOUVEAU_SVM_BIND_TARGET__GPU_VRAM:
148+
break;
149+
default:
150+
return -EINVAL;
151+
}
152+
153+
/*
154+
* FIXME: For now refuse non 0 stride, we need to change the migrate
155+
* kernel function to handle stride to avoid to create a mess within
156+
* each device driver.
157+
*/
158+
if (args->stride)
159+
return -EINVAL;
160+
161+
size = ((unsigned long)args->npages) << PAGE_SHIFT;
162+
if ((args->va_start + size) <= args->va_start)
163+
return -EINVAL;
164+
if ((args->va_start + size) > args->va_end)
165+
return -EINVAL;
166+
167+
/*
168+
* Ok we are ask to do something sane, for now we only support migrate
169+
* commands but we will add things like memory policy (what to do on
170+
* page fault) and maybe some other commands.
171+
*/
172+
173+
mm = get_task_mm(current);
174+
down_read(&mm->mmap_sem);
175+
176+
for (addr = args->va_start, end = args->va_start + size; addr < end;) {
177+
struct vm_area_struct *vma;
178+
unsigned long next;
179+
180+
vma = find_vma_intersection(mm, addr, end);
181+
if (!vma)
182+
break;
183+
184+
next = min(vma->vm_end, end);
185+
/* This is a best effort so we ignore errors */
186+
nouveau_dmem_migrate_vma(cli->drm, vma, addr, next);
187+
addr = next;
188+
}
189+
190+
/*
191+
* FIXME Return the number of page we have migrated, again we need to
192+
* update the migrate API to return that information so that we can
193+
* report it to user space.
194+
*/
195+
args->result = 0;
196+
197+
up_read(&mm->mmap_sem);
198+
mmput(mm);
199+
200+
return 0;
201+
}
202+
107203
/* Unlink channel instance from SVMM. */
108204
void
109205
nouveau_svmm_part(struct nouveau_svmm *svmm, u64 inst)

drivers/gpu/drm/nouveau/nouveau_svm.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ int nouveau_svmm_init(struct drm_device *, void *, struct drm_file *);
1717
void nouveau_svmm_fini(struct nouveau_svmm **);
1818
int nouveau_svmm_join(struct nouveau_svmm *, u64 inst);
1919
void nouveau_svmm_part(struct nouveau_svmm *, u64 inst);
20+
int nouveau_svmm_bind(struct drm_device *, void *, struct drm_file *);
2021
#else /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
2122
static inline void nouveau_svm_init(struct nouveau_drm *drm) {}
2223
static inline void nouveau_svm_fini(struct nouveau_drm *drm) {}
@@ -37,5 +38,11 @@ static inline int nouveau_svmm_join(struct nouveau_svmm *svmm, u64 inst)
3738
}
3839

3940
static inline void nouveau_svmm_part(struct nouveau_svmm *svmm, u64 inst) {}
41+
42+
static inline int nouveau_svmm_bind(struct drm_device *device, void *p,
43+
struct drm_file *file)
44+
{
45+
return -ENOSYS;
46+
}
4047
#endif /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
4148
#endif

include/uapi/drm/nouveau_drm.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct drm_nouveau_gem_cpu_fini {
134134
#define DRM_NOUVEAU_GPUOBJ_FREE 0x06 /* deprecated */
135135
#define DRM_NOUVEAU_NVIF 0x07
136136
#define DRM_NOUVEAU_SVM_INIT 0x08
137+
#define DRM_NOUVEAU_SVM_BIND 0x09
137138
#define DRM_NOUVEAU_GEM_NEW 0x40
138139
#define DRM_NOUVEAU_GEM_PUSHBUF 0x41
139140
#define DRM_NOUVEAU_GEM_CPU_PREP 0x42
@@ -145,7 +146,49 @@ struct drm_nouveau_svm_init {
145146
__u64 unmanaged_size;
146147
};
147148

149+
struct drm_nouveau_svm_bind {
150+
__u64 header;
151+
__u64 va_start;
152+
__u64 va_end;
153+
__u64 npages;
154+
__u64 stride;
155+
__u64 result;
156+
__u64 reserved0;
157+
__u64 reserved1;
158+
};
159+
160+
#define NOUVEAU_SVM_BIND_COMMAND_SHIFT 0
161+
#define NOUVEAU_SVM_BIND_COMMAND_BITS 8
162+
#define NOUVEAU_SVM_BIND_COMMAND_MASK ((1 << 8) - 1)
163+
#define NOUVEAU_SVM_BIND_PRIORITY_SHIFT 8
164+
#define NOUVEAU_SVM_BIND_PRIORITY_BITS 8
165+
#define NOUVEAU_SVM_BIND_PRIORITY_MASK ((1 << 8) - 1)
166+
#define NOUVEAU_SVM_BIND_TARGET_SHIFT 16
167+
#define NOUVEAU_SVM_BIND_TARGET_BITS 32
168+
#define NOUVEAU_SVM_BIND_TARGET_MASK 0xffffffff
169+
170+
/*
171+
* Below is use to validate ioctl argument, userspace can also use it to make
172+
* sure that no bit are set beyond known fields for a given kernel version.
173+
*/
174+
#define NOUVEAU_SVM_BIND_VALID_BITS 48
175+
#define NOUVEAU_SVM_BIND_VALID_MASK ((1ULL << NOUVEAU_SVM_BIND_VALID_BITS) - 1)
176+
177+
178+
/*
179+
* NOUVEAU_BIND_COMMAND__MIGRATE: synchronous migrate to target memory.
180+
* result: number of page successfuly migrate to the target memory.
181+
*/
182+
#define NOUVEAU_SVM_BIND_COMMAND__MIGRATE 0
183+
184+
/*
185+
* NOUVEAU_SVM_BIND_HEADER_TARGET__GPU_VRAM: target the GPU VRAM memory.
186+
*/
187+
#define NOUVEAU_SVM_BIND_TARGET__GPU_VRAM (1UL << 31)
188+
189+
148190
#define DRM_IOCTL_NOUVEAU_SVM_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_SVM_INIT, struct drm_nouveau_svm_init)
191+
#define DRM_IOCTL_NOUVEAU_SVM_BIND DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_SVM_BIND, struct drm_nouveau_svm_bind)
149192

150193
#define DRM_IOCTL_NOUVEAU_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_NEW, struct drm_nouveau_gem_new)
151194
#define DRM_IOCTL_NOUVEAU_GEM_PUSHBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_PUSHBUF, struct drm_nouveau_gem_pushbuf)

0 commit comments

Comments
 (0)