diff --git a/src/intel/common/intel_pagefault.c b/src/intel/common/intel_pagefault.c new file mode 100644 index 00000000000..205014f13c1 --- /dev/null +++ b/src/intel/common/intel_pagefault.c @@ -0,0 +1,40 @@ +/* Copyright © 2026 Intel Corporation + * SPDX-License-Identifier: MIT + */ + +#include "intel_pagefault.h" + +const char * +intel_pagefault_access_to_string(enum intel_pagefault_access access) +{ + static const char *const lookup[] = { + [INTEL_PAGEFAULT_ACCESS_READ] = "Read", + [INTEL_PAGEFAULT_ACCESS_WRITE] = "Write", + [INTEL_PAGEFAULT_ACCESS_ATOMIC] = "Atomic", + }; + return lookup[access]; +} + +const char * +intel_pagefault_type_to_string(enum intel_pagefault_type type) +{ + static const char *const lookup[] = { + [INTEL_PAGEFAULT_TYPE_NOT_PRESENT] = "Not Present", + [INTEL_PAGEFAULT_TYPE_WRITE_ACCESS] = "Not Writable", + [INTEL_PAGEFAULT_TYPE_ATOMIC_ACCESS] = "Atomic", + }; + return lookup[type]; +} + +const char * +intel_pagefault_level_to_string(enum intel_pagefault_level level) +{ + static const char *const lookup[] = { + [INTEL_PAGEFAULT_LEVEL_PTE] = "PTE", + [INTEL_PAGEFAULT_LEVEL_PDE] = "PDE", + [INTEL_PAGEFAULT_LEVEL_PDP] = "PDP", + [INTEL_PAGEFAULT_LEVEL_PML4] = "PML4", + [INTEL_PAGEFAULT_LEVEL_PML5] = "PML5", + }; + return lookup[level]; +} diff --git a/src/intel/common/intel_pagefault.h b/src/intel/common/intel_pagefault.h new file mode 100644 index 00000000000..ec8ff4c778e --- /dev/null +++ b/src/intel/common/intel_pagefault.h @@ -0,0 +1,47 @@ +/* Copyright © 2026 Intel Corporation + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +enum intel_pagefault_access { + INTEL_PAGEFAULT_ACCESS_READ, + INTEL_PAGEFAULT_ACCESS_WRITE, + INTEL_PAGEFAULT_ACCESS_ATOMIC, +}; + +enum intel_pagefault_type { + INTEL_PAGEFAULT_TYPE_NOT_PRESENT, + INTEL_PAGEFAULT_TYPE_WRITE_ACCESS, + INTEL_PAGEFAULT_TYPE_ATOMIC_ACCESS, +}; + +enum intel_pagefault_level { + INTEL_PAGEFAULT_LEVEL_PTE, + INTEL_PAGEFAULT_LEVEL_PDE, + INTEL_PAGEFAULT_LEVEL_PDP, + INTEL_PAGEFAULT_LEVEL_PML4, + INTEL_PAGEFAULT_LEVEL_PML5, +}; + +struct intel_pagefault_info { + uint64_t address; + uint32_t precision; + enum intel_pagefault_access access; + enum intel_pagefault_type type; + enum intel_pagefault_level level; +}; + +struct intel_pagefault_buffer { + unsigned size; + struct intel_pagefault_info items[]; +}; + +const char * +intel_pagefault_access_to_string(enum intel_pagefault_access access); +const char * +intel_pagefault_type_to_string(enum intel_pagefault_type type); +const char * +intel_pagefault_level_to_string(enum intel_pagefault_level level); diff --git a/src/intel/common/meson.build b/src/intel/common/meson.build index 3d60799d977..6b551548e54 100644 --- a/src/intel/common/meson.build +++ b/src/intel/common/meson.build @@ -42,7 +42,9 @@ files_libintel_common = files( 'intel_uuid.h', 'intel_measure.c', 'intel_measure.h', - 'intel_pixel_hash.h' + 'intel_pixel_hash.h', + 'intel_pagefault.c', + 'intel_pagefault.h', ) libintel_common_links = [libisl] diff --git a/src/intel/common/xe/intel_gem.c b/src/intel/common/xe/intel_gem.c index 81c7c345ace..29720125d84 100644 --- a/src/intel/common/xe/intel_gem.c +++ b/src/intel/common/xe/intel_gem.c @@ -29,6 +29,9 @@ #include "util/os_time.h" #include "util/timespec.h" +#include "util/compiler.h" +#include "util/macros.h" +#include "util/stack_array.h" bool xe_gem_read_render_timestamp(int fd, uint64_t *value) @@ -123,3 +126,92 @@ xe_gem_supports_protected_exec_queue(int fd) */ return intel_ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) == 0; } + +bool xe_gem_supports_get_vm_faults(int fd) +{ + struct drm_xe_vm_get_property prop = { + .vm_id = -1, + .property = DRM_XE_VM_GET_PROPERTY_FAULTS, + }; + /* FIXME: Get a proper kernel api to detect this */ + int ret = intel_ioctl(fd, DRM_IOCTL_XE_VM_GET_PROPERTY, &prop); + return ret == -1 && errno == ENOENT; +} + +static inline enum intel_pagefault_access +xe_vm_fault_get_access(const struct xe_vm_fault *vm_fault) +{ + switch (vm_fault->access_type) { + default: UNREACHABLE("not handled"); FALLTHROUGH; + case FAULT_ACCESS_TYPE_READ: return INTEL_PAGEFAULT_ACCESS_READ; + case FAULT_ACCESS_TYPE_WRITE: return INTEL_PAGEFAULT_ACCESS_WRITE; + case FAULT_ACCESS_TYPE_ATOMIC: return INTEL_PAGEFAULT_ACCESS_ATOMIC; + } +} + +static inline enum intel_pagefault_type +xe_vm_fault_get_type(const struct xe_vm_fault *vm_fault) +{ + switch (vm_fault->fault_type) { + default: UNREACHABLE("not handled"); FALLTHROUGH; + case FAULT_TYPE_NOT_PRESENT: return INTEL_PAGEFAULT_TYPE_NOT_PRESENT; + case FAULT_TYPE_WRITE_ACCESS: return INTEL_PAGEFAULT_TYPE_WRITE_ACCESS; + case FAULT_TYPE_ATOMIC_ACCESS: return INTEL_PAGEFAULT_TYPE_ATOMIC_ACCESS; + } +} + +static inline enum intel_pagefault_level +xe_vm_fault_get_level(const struct xe_vm_fault *vm_fault) +{ + switch (vm_fault->fault_level) { + default: UNREACHABLE("not handled"); FALLTHROUGH; + case FAULT_LEVEL_PTE: return INTEL_PAGEFAULT_LEVEL_PTE; + case FAULT_LEVEL_PDE: return INTEL_PAGEFAULT_LEVEL_PDE; + case FAULT_LEVEL_PDP: return INTEL_PAGEFAULT_LEVEL_PDP; + case FAULT_LEVEL_PML4: return INTEL_PAGEFAULT_LEVEL_PML4; + case FAULT_LEVEL_PML5: return INTEL_PAGEFAULT_LEVEL_PML5; + } +} + +struct intel_pagefault_buffer * +xe_gem_alloc_get_vm_faults(int fd, int vm_id) +{ + struct drm_xe_vm_get_property prop = { + .vm_id = vm_id, + .property = DRM_XE_VM_GET_PROPERTY_FAULTS, + }; + + int ret = intel_ioctl(fd, DRM_IOCTL_XE_VM_GET_PROPERTY, &prop); + if (ret) + return NULL; + + unsigned size = (unsigned) (prop.size / sizeof(struct xe_vm_fault)); + + STACK_ARRAY(struct xe_vm_fault, kmd_faults, size); + prop.size = size * sizeof(struct xe_vm_fault); + prop.data = (uintptr_t) kmd_faults; + + struct intel_pagefault_buffer *result = NULL; + + if (size != 0) + ret = intel_ioctl(fd, DRM_IOCTL_XE_VM_GET_PROPERTY, &prop); + + if (ret == 0) { + size = MIN2(size, (unsigned) (prop.size / sizeof(struct xe_vm_fault))); + result = malloc(sizeof(*result) + sizeof(result->items[0]) * size); + if (result) { + result->size = size; + for (unsigned i = 0; i < size; ++i) { + result->items[i].address = kmd_faults[i].address; + result->items[i].precision = kmd_faults[i].address_precision; + result->items[i].access = xe_vm_fault_get_access(&kmd_faults[i]); + result->items[i].type = xe_vm_fault_get_type(&kmd_faults[i]); + result->items[i].level = xe_vm_fault_get_level(&kmd_faults[i]); + } + } + } + + STACK_ARRAY_FINISH(kmd_faults); + + return result; +} diff --git a/src/intel/common/xe/intel_gem.h b/src/intel/common/xe/intel_gem.h index c65a527f737..1f8dd8a12e7 100644 --- a/src/intel/common/xe/intel_gem.h +++ b/src/intel/common/xe/intel_gem.h @@ -29,6 +29,7 @@ #include "common/intel_gem.h" #include "common/intel_engine.h" +#include "common/intel_pagefault.h" #include "drm-uapi/xe_drm.h" #include "util/os_time.h" @@ -43,9 +44,13 @@ xe_gem_read_correlate_cpu_gpu_timestamp(int fd, uint64_t *cpu_delta); bool xe_gem_can_render_on_fd(int fd); bool xe_gem_supports_protected_exec_queue(int fd); +bool xe_gem_supports_get_vm_faults(int fd); void intel_xe_gem_add_ext(uint64_t *ptr, uint32_t ext_name, void *data); +struct intel_pagefault_buffer * +xe_gem_alloc_get_vm_faults(int fd, int vm_id); + static inline int xe_gem_exec_ioctl(int fd, const struct intel_device_info *info, struct drm_xe_exec *exec)