From: "Bernatowicz, Marcin" <marcin.bernatowicz@linux.intel.com>
To: Lukasz Laguna <lukasz.laguna@intel.com>, igt-dev@lists.freedesktop.org
Cc: michal.wajdeczko@intel.com, michal.winiarski@intel.com,
satyanarayana.k.v.p@intel.com, adam.miszczak@linux.intel.com,
jakub1.kolakowski@intel.com
Subject: Re: [PATCH i-g-t 2/4] lib/intel_vram: Add library for VRAM accesses
Date: Thu, 21 Aug 2025 22:26:53 +0200 [thread overview]
Message-ID: <c52ed674-bb65-4a08-8b50-38822a1cbfa0@linux.intel.com> (raw)
In-Reply-To: <20250717090812.28628-3-lukasz.laguna@intel.com>
On 7/17/2025 11:08 AM, Lukasz Laguna wrote:
Hi Łukasz,
Thanks for the patch. I feel guilty as a co-author of the original code,
but since we are moving it into a library maybe we can do a few small
API tweaks to make it safer on 32-bit and easier to extend.
> Prepare a library with helpers to map and unmap VRAM BAR region and
> perform read/write operations.
>
> Signed-off-by: Lukasz Laguna <lukasz.laguna@intel.com>
> ---
> lib/intel_vram.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++
> lib/intel_vram.h | 22 ++++++
> lib/meson.build | 1 +
> 3 files changed, 206 insertions(+)
> create mode 100644 lib/intel_vram.c
> create mode 100644 lib/intel_vram.h
>
> diff --git a/lib/intel_vram.c b/lib/intel_vram.c
> new file mode 100644
> index 000000000..38e2ccf36
> --- /dev/null
> +++ b/lib/intel_vram.c
> @@ -0,0 +1,183 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2025 Intel Corporation
> + */
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <sys/mman.h>
> +#include <sys/stat.h>
> +
> +#include "igt_core.h"
> +#include "igt_sriov_device.h"
> +#include "intel_vram.h"
> +
> +static int intel_vram_open_bar(int pf_fd, unsigned int vf_num, int mode)
> +{
> + int sysfs, fd;
> +
> + sysfs = igt_sriov_device_sysfs_open(pf_fd, vf_num);
> + if (sysfs < 0) {
> + igt_debug("Failed to open sysfs for VF%d: %s\n", vf_num, strerror(errno));
> + return -1;
> + }
> +
> + fd = openat(sysfs, "resource2", mode | O_SYNC);
O_SYNC has no effect on mmap, can be dropped.
> + if (fd < 0)
> + igt_debug("Failed to open resource2 for VF%d: %s\n", vf_num, strerror(errno));
> +
> + close(sysfs);
> +
> + return fd;
> +}
> +
> +/**
> + * intel_vram_bar_size - Get the size of the VRAM BAR
> + * @pf_fd: PF device file descriptor
> + * @vf_num: VF number (1-based), or 0 for the PF
> + *
> + * Opens the VRAM BAR file descriptor for the specified device and retrieves
> + * its size by using fstat().
> + *
> + * Return: The size of the VRAM BAR in bytes on success,
> + * or negative value on failure.
> + */
> +ssize_t intel_vram_bar_size(int pf_fd, unsigned int vf_num)
> +{
> + int fd;
> + struct stat st;
> +
> + fd = intel_vram_open_bar(pf_fd, vf_num, O_RDONLY);
> + if (fd < 0)
> + return fd;
> +
> + if (fstat(fd, &st)) {
> + igt_debug("Failed to stat resource2 for VF%u: %s\n", vf_num, strerror(errno));
> + close(fd);
> + return -1;
> + }
> +
> + close(fd);
> +
> + return st.st_size;
> +}
Using ssize_t may be problematic: on 32-bit it truncates BARs >2 GiB.
maybe return int and fill a uint64_t *out_size.
int intel_vram_bar_size(int pf_fd, unsigned int vf_num, uint64_t *out_size)
{
int fd;
if (!out_size)
return -EINVAL;
fd = intel_vram_open_bar(pf_fd, vf_num, O_RDONLY);
if (fd < 0)
return fd;
struct stat st;
if (fstat(fd, &st)) {
int saved_err = errno;
close(fd);
return -saved_err;
}
close(fd);
if (st.st_size < 0)
return -EOVERFLOW;
*out_size = (uint64_t)st.st_size;
return 0;
}
> +
> +/**
> + * intel_vram_mmap - Map VRAM BAR region
> + * @pf_fd: PF device file descriptor
> + * @vf_num: VF number (1-based), or 0 for the PF
> + * @length: Number of bytes to map
> + * @prot: Memory protection flags
> + * @offset: Offset (in bytes) within the BAR to begin the mapping
> + *
> + * Maps a PF or VF VRAM BAR into user space using mmap().
> + *
> + * Return: A vram_mapping struct with the mapped address and size on success,
> + * or NULL address and zero size on failure.
> + */
> +struct vram_mapping intel_vram_mmap(int pf_fd, unsigned int vf_num, size_t length, int prot,
> + off_t offset)
Returning struct by value hides error codes and may be problematic to
changes (ex. extending fields). As it's a library maybe better to return
int (for error codes and let callers branch on cause, assert) and fill a
pointer to struct. Also, offsets are unsigned and large, maybe use
uint64_t for offset in the API, and cast down to off_t only at mmap().
> +{
> + int open_flags = ((prot & PROT_WRITE) != 0) ? O_RDWR : O_RDONLY;
> + struct vram_mapping m = { .addr = NULL, .size = 0 };
> + ssize_t vram_bar_size;
> + int vram_bar_fd;
> + void *addr;
> +
> + vram_bar_size = intel_vram_bar_size(pf_fd, vf_num);
> + if (vram_bar_size < 0) {
> + igt_debug("Failed to get VRAM BAR size for VF%u: %s\n", vf_num, strerror(errno));
> + return m;
> + }
> +
> + if (vram_bar_size < length) {
> + igt_debug("Mapping length (%zu) exceeds VRAM BAR size (%" PRIu64 ")\n",
> + length, (uint64_t)vram_bar_size);
> + return m;
> + }
Needs a proper range check: offset + length <= bar_size
> +
> + vram_bar_fd = intel_vram_open_bar(pf_fd, vf_num, open_flags);
> + if (vram_bar_fd < 0) {
> + igt_debug("Failed to open VRAM BAR file for VF%u: %s\n", vf_num, strerror(errno));
> + return m;
> + }
> +
> + addr = mmap(NULL, length, prot, MAP_SHARED, vram_bar_fd, offset);
> + close(vram_bar_fd);
> + if (addr == MAP_FAILED) {
> + igt_debug("Failed to map VRAM BAR for VF%u: %s\n", vf_num, strerror(errno));
> + return m;
> + }
> +
> + m.addr = addr;
> + m.size = length;
> + return m;
> +}
Proposed version:
int intel_vram_mmap(int pf_fd, unsigned int vf_num, uint64_t offset,
size_t length, int prot, struct vram_mapping *out)
{
uint64_t bar_size, end;
int fd, ret, saved_err;
void *addr;
if (!out)
return -EINVAL;
out->addr = NULL;
out->size = 0;
if (!length)
return 0;
ret = intel_vram_bar_size(pf_fd, vf_num, &bar_size);
if (ret)
return ret;
end = offset + (uint64_t)length;
if (end < offset || end > bar_size)
return -EINVAL;
fd = intel_vram_open_bar(pf_fd, vf_num,
(prot & PROT_WRITE) ? O_RDWR : O_RDONLY);
if (fd < 0)
return fd;
addr = mmap(NULL, length, prot, MAP_SHARED, fd, (off_t)offset);
saved_err = errno;
close(fd);
if (addr == MAP_FAILED)
return -saved_err;
out->addr = addr;
out->size = length;
return 0;
}
> +
> +/**
> + * intel_vram_munmap - Unmap previously mapped VRAM region
> + * @m: Pointer to a vram_mapping struct representing the mapped region
> + *
> + * Unmaps the user-space memory region previously mapped by intel_vram_mmap().
> + *
> + * Return: 0 on success, or negative value on failure.
> + */
> +int intel_vram_munmap(struct vram_mapping *m)
> +{
> + int ret;
> +
> + ret = munmap(m->addr, m->size);
> + if (ret < 0)
> + igt_debug("Failed munmap %p: %s\n", m->addr, strerror(errno));
> +
> + return ret;
> +}
> +
> +/**
> + * intel_vram_read8 - Read 8-bit value from a mapped VRAM region
> + * @m: Pointer to a vram_mapping struct representing the mapped region
> + * @offset: Offset (in bytes) to read from
> + *
> + * Reads a single 8-bit value from the specified offset in the mapped VRAM.
> + *
> + * Return: The 8-bit value read from the given offset.
> + */
> +uint8_t intel_vram_read8(struct vram_mapping *m, size_t offset)
> +{
> + igt_assert(offset < m->size);
> +
> + return READ_ONCE(*((uint8_t *)m->addr + offset));
> +}
> +
> +/**
> + * intel_vram_write8 - Write 8-bit value to a mapped VRAM region
> + * @m: Pointer to a vram_mapping struct representing the mapped region
> + * @offset: Offset (in bytes) to write to
> + * @value: The 8-bit value to write
> + *
> + * Writes a single 8-bit value to the specified offset in the mapped VRAM.
> + */
> +void intel_vram_write8(struct vram_mapping *m, size_t offset, uint8_t value)
> +{
> + igt_assert(offset < m->size);
> +
> + WRITE_ONCE(*((uint8_t *)m->addr + offset), value);
> +}
> +
> +/**
> + * intel_vram_write_readback8 - Write and then read back an 8-bit value
> + * @m: Pointer to a vram_mapping struct representing the mapped region
> + * @offset: Offset (in bytes) to write to and read from
> + * @value: The 8-bit value to write
> + *
> + * Writes an 8-bit value to the specified offset in the mapped VRAM and
> + * reads it back to verify if the write was successful.
> + *
> + * Return: The 8-bit value read back from the given offset.
> + */
> +uint8_t intel_vram_write_readback8(struct vram_mapping *m, size_t offset, uint8_t value)
> +{
> + intel_vram_write8(m, offset, value);
> + return intel_vram_read8(m, offset);
> +}
> diff --git a/lib/intel_vram.h b/lib/intel_vram.h
> new file mode 100644
> index 000000000..b93f915e9
> --- /dev/null
> +++ b/lib/intel_vram.h
> @@ -0,0 +1,22 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2025 Intel Corporation
> + */
> +
> +#ifndef __INTEL_VRAM_H__
> +#define __INTEL_VRAM_H__
> +
> +struct vram_mapping {
> + void *addr; /* Pointer to the mapped VRAM */
> + size_t size; /* Size of the mapped VRAM region */
> +};
> +
> +ssize_t intel_vram_bar_size(int pf_fd, unsigned int vf_num);
> +struct vram_mapping intel_vram_mmap(int pf_fd, unsigned int vf_num, size_t length, int prot,
> + off_t offset);
> +int intel_vram_munmap(struct vram_mapping *m);
> +uint8_t intel_vram_read8(struct vram_mapping *m, size_t offset);
> +void intel_vram_write8(struct vram_mapping *m, size_t offset, uint8_t value);
> +uint8_t intel_vram_write_readback8(struct vram_mapping *m, size_t offset, uint8_t value);
> +
Proposed API
/*
* Design choices:
*
* - Use uint64_t for BAR sizes/offsets (unsigned device semantics, no
truncation on 32-bit).
* - Functions return int (0 on success, -errno on failure).
* - No internal alignment: if offset isn’t page aligned, mmap() will
fail with EINVAL.
*/
int intel_vram_bar_size(int pf_fd, unsigned int vf_num, uint64_t
*out_size);
int intel_vram_mmap(int pf_fd, unsigned int vf_num,
uint64_t offset, size_t length, int prot,
struct vram_mapping *out);
...
> +#endif /* INTEL_VRAM_H */
> diff --git a/lib/meson.build b/lib/meson.build
> index 2eaca42a4..25c68011d 100644
> --- a/lib/meson.build
> +++ b/lib/meson.build
> @@ -70,6 +70,7 @@ lib_sources = [
> 'intel_mocs.c',
> 'igt_multigpu.c',
> 'intel_pat.c',
> + 'intel_vram.c',
> 'ioctl_wrappers.c',
> 'media_spin.c',
> 'media_fill.c',
next prev parent reply other threads:[~2025-08-21 20:27 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-17 9:08 [PATCH i-g-t 0/4] Validate VF accesses to VRAM via BAR Lukasz Laguna
2025-07-17 9:08 ` [PATCH i-g-t 1/4] lib/igt_sriov_device: Add helper to iterate over enabled VFs Lukasz Laguna
2025-07-21 10:05 ` Piotr Piórkowski
2025-07-17 9:08 ` [PATCH i-g-t 2/4] lib/intel_vram: Add library for VRAM accesses Lukasz Laguna
2025-08-21 20:26 ` Bernatowicz, Marcin [this message]
2025-07-17 9:08 ` [PATCH i-g-t 3/4] tests/intel/xe_sriov_flr: Use VRAM access helpers from intel_vram library Lukasz Laguna
2025-08-21 20:30 ` Bernatowicz, Marcin
2025-07-17 9:08 ` [PATCH i-g-t 4/4] tests/intel/xe_sriov_vram: Add test checking VF access to VRAM Lukasz Laguna
2025-07-31 8:29 ` Piotr Piórkowski
2025-08-01 12:43 ` Laguna, Lukasz
2025-08-21 16:53 ` Bernatowicz, Marcin
2025-08-27 13:16 ` Laguna, Lukasz
2025-07-17 12:42 ` ✓ i915.CI.BAT: success for Validate VF accesses to VRAM via BAR Patchwork
2025-07-17 13:56 ` ✓ Xe.CI.BAT: " Patchwork
2025-07-18 1:23 ` ✗ i915.CI.Full: failure " Patchwork
2025-07-18 19:07 ` ✗ Xe.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=c52ed674-bb65-4a08-8b50-38822a1cbfa0@linux.intel.com \
--to=marcin.bernatowicz@linux.intel.com \
--cc=adam.miszczak@linux.intel.com \
--cc=igt-dev@lists.freedesktop.org \
--cc=jakub1.kolakowski@intel.com \
--cc=lukasz.laguna@intel.com \
--cc=michal.wajdeczko@intel.com \
--cc=michal.winiarski@intel.com \
--cc=satyanarayana.k.v.p@intel.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.