intel: Add common utils for page fault reporting

Adds some data types and functions for getting the list of page faults
from the KMD using the intel common library.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41318>
This commit is contained in:
Calder Young 2026-04-08 14:26:43 -07:00 committed by Marge Bot
parent 5074524788
commit 39a0d76f64
5 changed files with 187 additions and 1 deletions

View file

@ -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];
}

View file

@ -0,0 +1,47 @@
/* Copyright © 2026 Intel Corporation
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <stdint.h>
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);

View file

@ -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]

View file

@ -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;
}

View file

@ -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)