mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 09:32:36 -04:00
Merge branch 'akpm' (patches from Andrew)
Merge more updates from Andrew Morton: "190 patches. Subsystems affected by this patch series: mm (hugetlb, userfaultfd, vmscan, kconfig, proc, z3fold, zbud, ras, mempolicy, memblock, migration, thp, nommu, kconfig, madvise, memory-hotplug, zswap, zsmalloc, zram, cleanups, kfence, and hmm), procfs, sysctl, misc, core-kernel, lib, lz4, checkpatch, init, kprobes, nilfs2, hfs, signals, exec, kcov, selftests, compress/decompress, and ipc" * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (190 commits) ipc/util.c: use binary search for max_idx ipc/sem.c: use READ_ONCE()/WRITE_ONCE() for use_global_lock ipc: use kmalloc for msg_queue and shmid_kernel ipc sem: use kvmalloc for sem_undo allocation lib/decompressors: remove set but not used variabled 'level' selftests/vm/pkeys: exercise x86 XSAVE init state selftests/vm/pkeys: refill shadow register after implicit kernel write selftests/vm/pkeys: handle negative sys_pkey_alloc() return code selftests/vm/pkeys: fix alloc_random_pkey() to make it really, really random kcov: add __no_sanitize_coverage to fix noinstr for all architectures exec: remove checks in __register_bimfmt() x86: signal: don't do sas_ss_reset() until we are certain that sigframe won't be abandoned hfsplus: report create_date to kstat.btime hfsplus: remove unnecessary oom message nilfs2: remove redundant continue statement in a while-loop kprobes: remove duplicated strong free_insn_page in x86 and s390 init: print out unknown kernel parameters checkpatch: do not complain about positive return values starting with EPOLL checkpatch: improve the indented label test checkpatch: scripts/spdxcheck.py now requires python3 ...
This commit is contained in:
@@ -77,6 +77,7 @@ struct nvif_vmm_pfnmap_v0 {
|
||||
#define NVIF_VMM_PFNMAP_V0_APER 0x00000000000000f0ULL
|
||||
#define NVIF_VMM_PFNMAP_V0_HOST 0x0000000000000000ULL
|
||||
#define NVIF_VMM_PFNMAP_V0_VRAM 0x0000000000000010ULL
|
||||
#define NVIF_VMM_PFNMAP_V0_A 0x0000000000000004ULL
|
||||
#define NVIF_VMM_PFNMAP_V0_W 0x0000000000000002ULL
|
||||
#define NVIF_VMM_PFNMAP_V0_V 0x0000000000000001ULL
|
||||
#define NVIF_VMM_PFNMAP_V0_NONE 0x0000000000000000ULL
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/hmm.h>
|
||||
#include <linux/rmap.h>
|
||||
|
||||
struct nouveau_svm {
|
||||
struct nouveau_drm *drm;
|
||||
@@ -67,6 +68,11 @@ struct nouveau_svm {
|
||||
} buffer[1];
|
||||
};
|
||||
|
||||
#define FAULT_ACCESS_READ 0
|
||||
#define FAULT_ACCESS_WRITE 1
|
||||
#define FAULT_ACCESS_ATOMIC 2
|
||||
#define FAULT_ACCESS_PREFETCH 3
|
||||
|
||||
#define SVM_DBG(s,f,a...) NV_DEBUG((s)->drm, "svm: "f"\n", ##a)
|
||||
#define SVM_ERR(s,f,a...) NV_WARN((s)->drm, "svm: "f"\n", ##a)
|
||||
|
||||
@@ -265,7 +271,7 @@ nouveau_svmm_invalidate_range_start(struct mmu_notifier *mn,
|
||||
* the invalidation is handled as part of the migration process.
|
||||
*/
|
||||
if (update->event == MMU_NOTIFY_MIGRATE &&
|
||||
update->migrate_pgmap_owner == svmm->vmm->cli->drm->dev)
|
||||
update->owner == svmm->vmm->cli->drm->dev)
|
||||
goto out;
|
||||
|
||||
if (limit > svmm->unmanaged.start && start < svmm->unmanaged.limit) {
|
||||
@@ -411,6 +417,24 @@ nouveau_svm_fault_cancel_fault(struct nouveau_svm *svm,
|
||||
fault->client);
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_svm_fault_priority(u8 fault)
|
||||
{
|
||||
switch (fault) {
|
||||
case FAULT_ACCESS_PREFETCH:
|
||||
return 0;
|
||||
case FAULT_ACCESS_READ:
|
||||
return 1;
|
||||
case FAULT_ACCESS_WRITE:
|
||||
return 2;
|
||||
case FAULT_ACCESS_ATOMIC:
|
||||
return 3;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_svm_fault_cmp(const void *a, const void *b)
|
||||
{
|
||||
@@ -421,9 +445,8 @@ nouveau_svm_fault_cmp(const void *a, const void *b)
|
||||
return ret;
|
||||
if ((ret = (s64)fa->addr - fb->addr))
|
||||
return ret;
|
||||
/*XXX: atomic? */
|
||||
return (fa->access == 0 || fa->access == 3) -
|
||||
(fb->access == 0 || fb->access == 3);
|
||||
return nouveau_svm_fault_priority(fa->access) -
|
||||
nouveau_svm_fault_priority(fb->access);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -487,6 +510,10 @@ static bool nouveau_svm_range_invalidate(struct mmu_interval_notifier *mni,
|
||||
struct svm_notifier *sn =
|
||||
container_of(mni, struct svm_notifier, notifier);
|
||||
|
||||
if (range->event == MMU_NOTIFY_EXCLUSIVE &&
|
||||
range->owner == sn->svmm->vmm->cli->drm->dev)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* serializes the update to mni->invalidate_seq done by caller and
|
||||
* prevents invalidation of the PTE from progressing while HW is being
|
||||
@@ -555,6 +582,71 @@ static void nouveau_hmm_convert_pfn(struct nouveau_drm *drm,
|
||||
args->p.phys[0] |= NVIF_VMM_PFNMAP_V0_W;
|
||||
}
|
||||
|
||||
static int nouveau_atomic_range_fault(struct nouveau_svmm *svmm,
|
||||
struct nouveau_drm *drm,
|
||||
struct nouveau_pfnmap_args *args, u32 size,
|
||||
struct svm_notifier *notifier)
|
||||
{
|
||||
unsigned long timeout =
|
||||
jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
|
||||
struct mm_struct *mm = svmm->notifier.mm;
|
||||
struct page *page;
|
||||
unsigned long start = args->p.addr;
|
||||
unsigned long notifier_seq;
|
||||
int ret = 0;
|
||||
|
||||
ret = mmu_interval_notifier_insert(¬ifier->notifier, mm,
|
||||
args->p.addr, args->p.size,
|
||||
&nouveau_svm_mni_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
while (true) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
notifier_seq = mmu_interval_read_begin(¬ifier->notifier);
|
||||
mmap_read_lock(mm);
|
||||
ret = make_device_exclusive_range(mm, start, start + PAGE_SIZE,
|
||||
&page, drm->dev);
|
||||
mmap_read_unlock(mm);
|
||||
if (ret <= 0 || !page) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&svmm->mutex);
|
||||
if (!mmu_interval_read_retry(¬ifier->notifier,
|
||||
notifier_seq))
|
||||
break;
|
||||
mutex_unlock(&svmm->mutex);
|
||||
}
|
||||
|
||||
/* Map the page on the GPU. */
|
||||
args->p.page = 12;
|
||||
args->p.size = PAGE_SIZE;
|
||||
args->p.addr = start;
|
||||
args->p.phys[0] = page_to_phys(page) |
|
||||
NVIF_VMM_PFNMAP_V0_V |
|
||||
NVIF_VMM_PFNMAP_V0_W |
|
||||
NVIF_VMM_PFNMAP_V0_A |
|
||||
NVIF_VMM_PFNMAP_V0_HOST;
|
||||
|
||||
svmm->vmm->vmm.object.client->super = true;
|
||||
ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, size, NULL);
|
||||
svmm->vmm->vmm.object.client->super = false;
|
||||
mutex_unlock(&svmm->mutex);
|
||||
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
|
||||
out:
|
||||
mmu_interval_notifier_remove(¬ifier->notifier);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nouveau_range_fault(struct nouveau_svmm *svmm,
|
||||
struct nouveau_drm *drm,
|
||||
struct nouveau_pfnmap_args *args, u32 size,
|
||||
@@ -567,18 +659,27 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
|
||||
unsigned long hmm_pfns[1];
|
||||
struct hmm_range range = {
|
||||
.notifier = ¬ifier->notifier,
|
||||
.start = notifier->notifier.interval_tree.start,
|
||||
.end = notifier->notifier.interval_tree.last + 1,
|
||||
.default_flags = hmm_flags,
|
||||
.hmm_pfns = hmm_pfns,
|
||||
.dev_private_owner = drm->dev,
|
||||
};
|
||||
struct mm_struct *mm = notifier->notifier.mm;
|
||||
struct mm_struct *mm = svmm->notifier.mm;
|
||||
int ret;
|
||||
|
||||
ret = mmu_interval_notifier_insert(¬ifier->notifier, mm,
|
||||
args->p.addr, args->p.size,
|
||||
&nouveau_svm_mni_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
range.start = notifier->notifier.interval_tree.start;
|
||||
range.end = notifier->notifier.interval_tree.last + 1;
|
||||
|
||||
while (true) {
|
||||
if (time_after(jiffies, timeout))
|
||||
return -EBUSY;
|
||||
if (time_after(jiffies, timeout)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
range.notifier_seq = mmu_interval_read_begin(range.notifier);
|
||||
mmap_read_lock(mm);
|
||||
@@ -587,7 +688,7 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
|
||||
if (ret) {
|
||||
if (ret == -EBUSY)
|
||||
continue;
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&svmm->mutex);
|
||||
@@ -606,6 +707,9 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
|
||||
svmm->vmm->vmm.object.client->super = false;
|
||||
mutex_unlock(&svmm->mutex);
|
||||
|
||||
out:
|
||||
mmu_interval_notifier_remove(¬ifier->notifier);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -625,7 +729,7 @@ nouveau_svm_fault(struct nvif_notify *notify)
|
||||
unsigned long hmm_flags;
|
||||
u64 inst, start, limit;
|
||||
int fi, fn;
|
||||
int replay = 0, ret;
|
||||
int replay = 0, atomic = 0, ret;
|
||||
|
||||
/* Parse available fault buffer entries into a cache, and update
|
||||
* the GET pointer so HW can reuse the entries.
|
||||
@@ -706,12 +810,14 @@ nouveau_svm_fault(struct nvif_notify *notify)
|
||||
/*
|
||||
* Determine required permissions based on GPU fault
|
||||
* access flags.
|
||||
* XXX: atomic?
|
||||
*/
|
||||
switch (buffer->fault[fi]->access) {
|
||||
case 0: /* READ. */
|
||||
hmm_flags = HMM_PFN_REQ_FAULT;
|
||||
break;
|
||||
case 2: /* ATOMIC. */
|
||||
atomic = true;
|
||||
break;
|
||||
case 3: /* PREFETCH. */
|
||||
hmm_flags = 0;
|
||||
break;
|
||||
@@ -727,14 +833,14 @@ nouveau_svm_fault(struct nvif_notify *notify)
|
||||
}
|
||||
|
||||
notifier.svmm = svmm;
|
||||
ret = mmu_interval_notifier_insert(¬ifier.notifier, mm,
|
||||
args.i.p.addr, args.i.p.size,
|
||||
&nouveau_svm_mni_ops);
|
||||
if (!ret) {
|
||||
if (atomic)
|
||||
ret = nouveau_atomic_range_fault(svmm, svm->drm,
|
||||
&args.i, sizeof(args),
|
||||
¬ifier);
|
||||
else
|
||||
ret = nouveau_range_fault(svmm, svm->drm, &args.i,
|
||||
sizeof(args), hmm_flags, ¬ifier);
|
||||
mmu_interval_notifier_remove(¬ifier.notifier);
|
||||
}
|
||||
sizeof(args), hmm_flags,
|
||||
¬ifier);
|
||||
mmput(mm);
|
||||
|
||||
limit = args.i.p.addr + args.i.p.size;
|
||||
@@ -750,11 +856,15 @@ nouveau_svm_fault(struct nvif_notify *notify)
|
||||
*/
|
||||
if (buffer->fault[fn]->svmm != svmm ||
|
||||
buffer->fault[fn]->addr >= limit ||
|
||||
(buffer->fault[fi]->access == 0 /* READ. */ &&
|
||||
(buffer->fault[fi]->access == FAULT_ACCESS_READ &&
|
||||
!(args.phys[0] & NVIF_VMM_PFNMAP_V0_V)) ||
|
||||
(buffer->fault[fi]->access != 0 /* READ. */ &&
|
||||
buffer->fault[fi]->access != 3 /* PREFETCH. */ &&
|
||||
!(args.phys[0] & NVIF_VMM_PFNMAP_V0_W)))
|
||||
(buffer->fault[fi]->access != FAULT_ACCESS_READ &&
|
||||
buffer->fault[fi]->access != FAULT_ACCESS_PREFETCH &&
|
||||
!(args.phys[0] & NVIF_VMM_PFNMAP_V0_W)) ||
|
||||
(buffer->fault[fi]->access != FAULT_ACCESS_READ &&
|
||||
buffer->fault[fi]->access != FAULT_ACCESS_WRITE &&
|
||||
buffer->fault[fi]->access != FAULT_ACCESS_PREFETCH &&
|
||||
!(args.phys[0] & NVIF_VMM_PFNMAP_V0_A)))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -178,6 +178,7 @@ void nvkm_vmm_unmap_region(struct nvkm_vmm *, struct nvkm_vma *);
|
||||
#define NVKM_VMM_PFN_APER 0x00000000000000f0ULL
|
||||
#define NVKM_VMM_PFN_HOST 0x0000000000000000ULL
|
||||
#define NVKM_VMM_PFN_VRAM 0x0000000000000010ULL
|
||||
#define NVKM_VMM_PFN_A 0x0000000000000004ULL
|
||||
#define NVKM_VMM_PFN_W 0x0000000000000002ULL
|
||||
#define NVKM_VMM_PFN_V 0x0000000000000001ULL
|
||||
#define NVKM_VMM_PFN_NONE 0x0000000000000000ULL
|
||||
|
||||
@@ -88,6 +88,9 @@ gp100_vmm_pgt_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
|
||||
if (!(*map->pfn & NVKM_VMM_PFN_W))
|
||||
data |= BIT_ULL(6); /* RO. */
|
||||
|
||||
if (!(*map->pfn & NVKM_VMM_PFN_A))
|
||||
data |= BIT_ULL(7); /* Atomic disable. */
|
||||
|
||||
if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) {
|
||||
addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT;
|
||||
addr = dma_map_page(dev, pfn_to_page(addr), 0,
|
||||
@@ -322,6 +325,9 @@ gp100_vmm_pd0_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
|
||||
if (!(*map->pfn & NVKM_VMM_PFN_W))
|
||||
data |= BIT_ULL(6); /* RO. */
|
||||
|
||||
if (!(*map->pfn & NVKM_VMM_PFN_A))
|
||||
data |= BIT_ULL(7); /* Atomic disable. */
|
||||
|
||||
if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) {
|
||||
addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT;
|
||||
addr = dma_map_page(dev, pfn_to_page(addr), 0,
|
||||
|
||||
Reference in New Issue
Block a user