diff mbox series

[i-g-t,02/12] lib/i915/intel_memory_region: Add memory regions stubs

Message ID 20210511165117.428062-3-matthew.auld@intel.com (mailing list archive)
State New, archived
Headers show
Series DG1/LMEM uAPI basics | expand

Commit Message

Matthew Auld May 11, 2021, 4:51 p.m. UTC
From: Andrzej Turko <andrzej.turko@linux.intel.com>

Added stubs for memory regions to make upstreaming of tests which are
using this interface possible.

The memory region uapi implementation in the driver is not stable yet.
Thus, the full memory region interface cannot be used in lib. This
commit adds stubs for this uapi to be used in tests. This way future
introduction of the full memory regions uapi will trigger
much smaller changes in tests.

Signed-off-by: Andrzej Turko <andrzej.turko@linux.intel.com>
Cc: Zbigniew Kempczynski <zbigniew.kempczynski@intel.com>
Cc: Dominik Grzegorzek <dominik.grzegorzek@intel.com>
Cc: Petri Latvala <petri.latvala@intel.com>
---
 lib/i915/intel_memory_region.c | 399 +++++++++++++++++++++++++++++++++
 lib/i915/intel_memory_region.h | 220 ++++++++++++++++++
 lib/ioctl_wrappers.h           |   1 +
 lib/meson.build                |   1 +
 4 files changed, 621 insertions(+)
 create mode 100644 lib/i915/intel_memory_region.c
 create mode 100644 lib/i915/intel_memory_region.h
diff mbox series

Patch

diff --git a/lib/i915/intel_memory_region.c b/lib/i915/intel_memory_region.c
new file mode 100644
index 00000000..5452dd8e
--- /dev/null
+++ b/lib/i915/intel_memory_region.c
@@ -0,0 +1,399 @@ 
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/limits.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysinfo.h>
+#include <fcntl.h>
+
+#include "i915/gem_create.h"
+#include "intel_reg.h"
+#include "drmtest.h"
+#include "ioctl_wrappers.h"
+#include "igt_dummyload.h"
+#include "igt_gt.h"
+#include "igt_params.h"
+#include "igt_sysfs.h"
+#include "intel_chipset.h"
+#include "igt_collection.h"
+#include "igt_device.h"
+#include "igt_aux.h"
+
+#include "i915/intel_memory_region.h"
+
+const char *get_memory_region_name(uint32_t region)
+{
+	uint16_t class = MEMORY_TYPE_FROM_REGION(region);
+
+	if (class == LOCAL_I915_MEMORY_CLASS_SYSTEM)
+		return "smem";
+
+	igt_assert_f(false, "Unknown memory region");
+}
+
+/**
+ *  gem_get_batch_size:
+ *  @fd: open i915 drm file descriptor
+ *  @mem_region_type: used memory_region type
+ */
+uint32_t gem_get_batch_size(int fd, uint8_t mem_region_type)
+{
+	/* temporary solution, to be erased later */
+	(void) fd;
+	(void) mem_region_type;
+
+	return 4096;
+}
+
+static uint64_t __get_meminfo(const char *info, const char *tag)
+{
+	const char *str;
+	unsigned long val;
+
+	str = strstr(info, tag);
+	if (str && sscanf(str + strlen(tag), " %lu", &val) == 1)
+		return (uint64_t)val << 10;
+
+	igt_warn("Unrecognized /proc/meminfo field: '%s'\n", tag);
+	return 0;
+}
+
+static uint64_t __get_available_smem(int fd)
+{
+	uint64_t retval;
+	char *info;
+	int proc_fd;
+
+	intel_purge_vm_caches(fd);
+
+	proc_fd = open("/proc", O_RDONLY);
+	info = igt_sysfs_get(proc_fd, "meminfo");
+	close(proc_fd);
+
+	if (info) {
+		retval = __get_meminfo(info, "MemAvailable:");
+	} else {
+		struct sysinfo sysinf;
+
+		igt_assert(sysinfo(&sysinf) == 0);
+		retval = sysinf.freeram;
+		retval *= sysinf.mem_unit;
+	}
+
+	return retval;
+}
+
+/**
+ * gem_get_query_memory_regions:
+ * @fd: open i915 drm file descriptor
+ *
+ * This function is prepared as a wrapper for the upcoming memory
+ * regions implementation.
+ *
+ * Returns: Filled struct with available memory regions.
+ */
+struct local_drm_i915_query_memory_regions *gem_get_query_memory_regions(int fd)
+{
+	struct local_drm_i915_query_memory_regions *query_info;
+
+	query_info = calloc(1, sizeof(struct local_drm_i915_query_memory_regions)
+			    + sizeof(struct local_drm_i915_memory_region_info));
+
+	query_info->num_regions = 1;
+	query_info->regions[0].region.memory_class = LOCAL_I915_MEMORY_CLASS_SYSTEM;
+	query_info->regions[0].probed_size = intel_get_total_ram_mb() << 20;
+	query_info->regions[0].unallocated_size = __get_available_smem(fd);
+
+	return query_info;
+}
+
+/* A version of gem_create_in_memory_region_list which can be allowed to
+   fail so that the object creation can be retried */
+int __gem_create_in_memory_region_list(int fd, uint32_t *handle, uint64_t size,
+				       struct local_drm_i915_gem_memory_class_instance *mem_regions,
+				       int num_regions)
+{
+	/* a temporary solution, to be removed when these arguments will be used */
+	(void) mem_regions;
+	(void) num_regions;
+
+	return __gem_create(fd, &size, handle);
+}
+
+/* gem_create_in_memory_region_list:
+ * @fd: opened i915 drm file descriptor
+ * @size: requested size of the buffer
+ * @mem_regions: memory regions array (priority list)
+ * @num_regions: @mem_regions length
+ */
+uint32_t gem_create_in_memory_region_list(int fd, uint64_t size,
+					  struct local_drm_i915_gem_memory_class_instance *mem_regions,
+					  int num_regions)
+{
+	uint32_t handle;
+	int ret = __gem_create_in_memory_region_list(fd, &handle, size,
+						     mem_regions, num_regions);
+	igt_assert_eq(ret, 0);
+	return handle;
+}
+
+static bool __region_belongs_to_regions_type(struct local_drm_i915_gem_memory_class_instance region,
+					     uint32_t *mem_regions_type,
+					     int num_regions)
+{
+	for (int i = 0; i < num_regions; i++)
+		if (mem_regions_type[i] == region.memory_class)
+			return true;
+	return false;
+}
+
+struct igt_collection *
+__get_memory_region_set(struct local_drm_i915_query_memory_regions *regions,
+			uint32_t *mem_regions_type,
+			int num_regions)
+{
+	struct local_drm_i915_gem_memory_class_instance region;
+	struct igt_collection *set;
+	int count = 0, pos = 0;
+
+	for (int i = 0; i < regions->num_regions; i++) {
+		region = regions->regions[i].region;
+		if (__region_belongs_to_regions_type(region,
+						     mem_regions_type,
+						     num_regions))
+			count++;
+	}
+
+	set = igt_collection_create(count);
+
+	for (int i = 0; i < regions->num_regions; i++) {
+		region = regions->regions[i].region;
+		if (__region_belongs_to_regions_type(region,
+						     mem_regions_type,
+						     num_regions))
+			igt_collection_set_value(set, pos++,
+						 INTEL_MEMORY_REGION_ID(region.memory_class,
+									region.memory_instance));
+	}
+
+	igt_assert(count == pos);
+
+	return set;
+}
+
+/**
+  * memregion_dynamic_subtest_name:
+  * @igt_collection: memory region collection
+  *
+  * Function iterates over all memory regions inside the collection (keeped
+  * in the value field) and generates the name which can be used during dynamic
+  * subtest creation.
+  *
+  * Returns: newly allocated string, has to be freed by caller. Asserts if
+  * caller tries to create a name using empty collection.
+  */
+char *memregion_dynamic_subtest_name(struct igt_collection *set)
+{
+	struct igt_collection_data *data;
+	char *name, *p;
+	uint32_t region, len;
+
+	igt_assert(set && set->size);
+	/* enough for "name%d-" * n */
+	len = set->size * 8;
+	p = name = malloc(len);
+	igt_assert(name);
+
+	for_each_collection_data(data, set) {
+		int r;
+
+		region = data->value;
+
+		r = snprintf(p, len, "%s-", get_memory_region_name(region));
+
+		igt_assert(r > 0);
+		p += r;
+		len -= r;
+	}
+
+	/* remove last '-' */
+	*(p - 1) = 0;
+
+	return name;
+}
+
+/**
+ * intel_dump_gpu_meminfo:
+ * @info: pointer to drm_i915_query_memory_regions structure
+ *
+ * Outputs memory regions and their sizes.
+ */
+void intel_dump_gpu_meminfo(struct local_drm_i915_query_memory_regions *info)
+{
+	int i;
+
+	igt_assert(info);
+
+	igt_info("GPU meminfo:\n");
+
+	for (i = 0; i < info->num_regions; i++) {
+		uint32_t region = INTEL_MEMORY_REGION_ID(info->regions[i].region.memory_class,
+							 info->regions[i].region.memory_instance);
+		const char *name = get_memory_region_name(region);
+
+		igt_info("- %s [%d] memory [size: 0x%llx, available: 0x%llx]\n",
+			 name, info->regions[i].region.memory_instance,
+			 info->regions[i].probed_size,
+			 info->regions[i].unallocated_size);
+	}
+}
+
+/**
+ * gpu_meminfo_region_count:
+ * @info: pointer to drm_i915_query_memory_regions structure
+ * @memory_class: memory region class
+ *
+ * Returns: number of regions for type @memory_class
+ */
+uint32_t gpu_meminfo_region_count(struct local_drm_i915_query_memory_regions *info,
+				  uint16_t memory_class)
+{
+	uint32_t num = 0;
+	int i;
+
+	igt_assert(info);
+
+	for (i = 0; i < info->num_regions; i++)
+		if (info->regions[i].region.memory_class == memory_class)
+			num++;
+
+	return num;
+}
+
+/**
+ * gpu_meminfo_region_total_size:
+ * @info: pointer to drm_i915_query_memory_regions structure
+ * @memory_class: memory region class
+ *
+ * Returns: total size of all regions which are type @memory_class, -1 when the
+ * size of at least one region is unknown
+ */
+uint64_t gpu_meminfo_region_total_size(struct local_drm_i915_query_memory_regions *info,
+				       uint16_t memory_class)
+{
+	uint64_t total = 0;
+	int i;
+
+	igt_assert(info);
+
+	for (i = 0; i < info->num_regions; i++)
+		if (info->regions[i].region.memory_class == memory_class) {
+			if (info->regions[i].probed_size == -1)
+				return -1;
+
+			total += info->regions[i].probed_size;
+		}
+
+	return total;
+}
+
+/**
+ * gpu_meminfo_region_total_available:
+ * @info: pointer to drm_i915_query_memory_regions structure
+ * @memory_class: memory region class
+ *
+ * Returns: available size of all regions which are type @memory_class, -1 when
+ * the size of at least one region cannot be estimated
+ */
+uint64_t gpu_meminfo_region_total_available(struct local_drm_i915_query_memory_regions *info,
+					    uint16_t memory_class)
+{
+	uint64_t avail = 0;
+	int i;
+
+	igt_assert(info);
+
+	for (i = 0; i < info->num_regions; i++)
+		if (info->regions[i].region.memory_class == memory_class) {
+			if (info->regions[i].unallocated_size == -1)
+				return -1;
+
+			avail += info->regions[i].unallocated_size;
+		}
+
+	return avail;
+}
+
+/**
+ * gpu_meminfo_region_size:
+ * @info: pointer to drm_i915_query_memory_regions structure
+ * @memory_class: memory region class
+ * @memory_instance: memory region instance
+ *
+ * Returns: available size of @memory_instance which type is @memory_class, -1
+ * when the size is unknown
+ */
+uint64_t gpu_meminfo_region_size(struct local_drm_i915_query_memory_regions *info,
+				 uint16_t memory_class,
+				 uint16_t memory_instance)
+{
+	int i;
+
+	igt_assert(info);
+
+	for (i = 0; i < info->num_regions; i++)
+		if (info->regions[i].region.memory_class == memory_class &&
+		     info->regions[i].region.memory_instance == memory_instance)
+			return info->regions[i].probed_size;
+
+	return 0;
+}
+
+/**
+ * gpu_meminfo_region_available:
+ * @info: pointer to drm_i915_query_memory_regions structure
+ * @memory_class: memory region class
+ * @memory_instance: memory region instance
+ *
+ * Returns: available size of @memory_instance region which type is
+ * @memory_class, -1 when the size cannot be estimated
+ */
+uint64_t gpu_meminfo_region_available(struct local_drm_i915_query_memory_regions *info,
+				      uint16_t memory_class,
+				      uint16_t memory_instance)
+{
+	int i;
+
+	igt_assert(info);
+
+	for (i = 0; i < info->num_regions; i++)
+		if (info->regions[i].region.memory_class == memory_class &&
+		     info->regions[i].region.memory_instance == memory_instance)
+			return info->regions[i].unallocated_size;
+
+	return 0;
+}
diff --git a/lib/i915/intel_memory_region.h b/lib/i915/intel_memory_region.h
new file mode 100644
index 00000000..b8ea22b5
--- /dev/null
+++ b/lib/i915/intel_memory_region.h
@@ -0,0 +1,220 @@ 
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "igt_collection.h"
+
+#ifndef INTEL_MEMORY_REGION_H
+#define INTEL_MEMORY_REGION_H
+
+#define I915_SYSTEM_MEMORY LOCAL_I915_MEMORY_CLASS_SYSTEM
+
+#define INTEL_MEMORY_REGION_ID(type, instance) ((type) << 16u | (instance))
+#define MEMORY_TYPE_FROM_REGION(r) ((r) >> 16u)
+#define MEMORY_INSTANCE_FROM_REGION(r) ((r) & 0xffff)
+
+#define IS_MEMORY_REGION_TYPE(region, type) \
+	(MEMORY_TYPE_FROM_REGION(region) == type)
+
+#define IS_SYSTEM_MEMORY_REGION(region) \
+	IS_MEMORY_REGION_TYPE(region, LOCAL_I915_MEMORY_CLASS_SYSTEM)
+
+#define REGION_SMEM    INTEL_MEMORY_REGION_ID(LOCAL_I915_MEMORY_CLASS_SYSTEM, 0)
+
+/**
+ * enum drm_i915_gem_memory_class - Supported memory classes
+ */
+enum local_drm_i915_gem_memory_class {
+	/** @I915_MEMORY_CLASS_SYSTEM: System memory */
+	LOCAL_I915_MEMORY_CLASS_SYSTEM = 0,
+	/** @I915_MEMORY_CLASS_DEVICE: Device local-memory */
+	LOCAL_I915_MEMORY_CLASS_DEVICE,
+};
+
+/**
+ * struct drm_i915_gem_memory_class_instance - Identify particular memory region
+ */
+struct local_drm_i915_gem_memory_class_instance {
+	/** @memory_class: See enum drm_i915_gem_memory_class */
+	__u16 memory_class;
+
+	/** @memory_instance: Which instance */
+	__u16 memory_instance;
+};
+
+/**
+ * struct drm_i915_memory_region_info - Describes one region as known to the
+ * driver.
+ *
+ * Note that we reserve some stuff here for potential future work. As an example
+ * we might want expose the capabilities(see @caps) for a given region, which
+ * could include things like if the region is CPU mappable/accessible, what are
+ * the supported mapping types etc.
+ *
+ * Note this is using both struct drm_i915_query_item and struct drm_i915_query.
+ * For this new query we are adding the new query id DRM_I915_QUERY_MEMORY_REGIONS
+ * at &drm_i915_query_item.query_id.
+ */
+struct local_drm_i915_memory_region_info {
+	/** @region: The class:instance pair encoding */
+	struct local_drm_i915_gem_memory_class_instance region;
+
+	/** @pad: MBZ */
+	__u32 pad;
+
+	/** @caps: MBZ */
+	__u64 caps;
+
+	/** @probed_size: Memory probed by the driver (-1 = unknown) */
+	__u64 probed_size;
+
+	/** @unallocated_size: Estimate of memory remaining (-1 = unknown) */
+	__u64 unallocated_size;
+};
+
+/**
+ * struct drm_i915_query_memory_regions
+ *
+ * The region info query enumerates all regions known to the driver by filling
+ * in an array of struct drm_i915_memory_region_info structures.
+ *
+ * Example for getting the list of supported regions:
+ *
+ * .. code-block:: C
+ *
+ *	struct drm_i915_query_memory_regions *info;
+ *	struct drm_i915_query_item item = {
+ *		.query_id = DRM_I915_QUERY_MEMORY_REGIONS;
+ *	};
+ *	struct drm_i915_query query = {
+ *		.num_items = 1,
+ *		.items_ptr = (uintptr_t)&item,
+ *	};
+ *	int err, i;
+ *
+ *	// First query the size of the blob we need, this needs to be large
+ *	// enough to hold our array of regions. The kernel will fill out the
+ *	// item.length for us, which is the number of bytes we need.
+ *	err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query);
+ *	if (err) ...
+ *
+ *	info = calloc(1, item.length);
+ *	// Now that we allocated the required number of bytes, we call the ioctl
+ *	// again, this time with the data_ptr pointing to our newly allocated
+ *	// blob, which the kernel can then populate with the all the region info.
+ *	item.data_ptr = (uintptr_t)&info,
+ *
+ *	err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query);
+ *	if (err) ...
+ *
+ *	// We can now access each region in the array
+ *	for (i = 0; i < info->num_regions; i++) {
+ *		struct drm_i915_memory_region_info mr = info->regions[i];
+ *		u16 class = mr.region.class;
+ *		u16 instance = mr.region.instance;
+ *
+ *		....
+ *	}
+ *
+ *	free(info);
+ */
+struct local_drm_i915_query_memory_regions {
+	/** @num_regions: Number of supported regions */
+	__u32 num_regions;
+
+	/** @pad: MBZ */
+	__u32 pad;
+
+	/** @regions: Info about each supported region */
+	struct local_drm_i915_memory_region_info regions[];
+};
+
+const char *get_memory_region_name(uint32_t region);
+uint32_t gem_get_batch_size(int fd, uint8_t mem_region_type);
+
+struct local_drm_i915_query_memory_regions *gem_get_query_memory_regions(int fd);
+
+
+int __gem_create_in_memory_region_list(int fd, uint32_t *handle, uint64_t size,
+				       struct local_drm_i915_gem_memory_class_instance *mem_regions,
+				       int num_regions);
+
+uint32_t gem_create_in_memory_region_list(int fd, uint64_t size,
+					  struct local_drm_i915_gem_memory_class_instance *mem_regions,
+					  int num_regions);
+
+/*
+ * XXX: the whole converting to class_instance thing is meant as a temporary
+ * stop gap which should keep everything working, such that we don't have to
+ * rewrite the world in one go to fit the new uAPI.
+ */
+#define __gem_create_in_memory_regions(fd, handle, size, regions...) ({ \
+	unsigned int arr__[] = { regions }; \
+	struct local_drm_i915_gem_memory_class_instance arr_query__[ARRAY_SIZE(arr__)]; \
+	for (int i__  = 0; i__ < ARRAY_SIZE(arr_query__); ++i__) { \
+		arr_query__[i__].memory_class = MEMORY_TYPE_FROM_REGION(arr__[i__]);  \
+		arr_query__[i__].memory_instance = MEMORY_INSTANCE_FROM_REGION(arr__[i__]);  \
+	} \
+	__gem_create_in_memory_region_list(fd, handle, size, arr_query__, ARRAY_SIZE(arr_query__)); \
+})
+#define gem_create_in_memory_regions(fd, size, regions...) ({ \
+	unsigned int arr__[] = { regions }; \
+	struct local_drm_i915_gem_memory_class_instance arr_query__[ARRAY_SIZE(arr__)]; \
+	for (int i__  = 0; i__ < ARRAY_SIZE(arr_query__); ++i__) { \
+		arr_query__[i__].memory_class = MEMORY_TYPE_FROM_REGION(arr__[i__]);  \
+		arr_query__[i__].memory_instance = MEMORY_INSTANCE_FROM_REGION(arr__[i__]);  \
+	} \
+	gem_create_in_memory_region_list(fd, size, arr_query__, ARRAY_SIZE(arr_query__)); \
+})
+
+struct igt_collection *
+__get_memory_region_set(struct local_drm_i915_query_memory_regions *regions,
+			uint32_t *mem_regions_type,
+			int num_regions);
+
+/*
+ * Helper macro to create igt_collection which contains all memory regions
+ * which matches mem_region_types array.
+ */
+#define get_memory_region_set(regions, mem_region_types...) ({ \
+	unsigned int arr__[] = { mem_region_types }; \
+	__get_memory_region_set(regions, arr__, ARRAY_SIZE(arr__)); \
+})
+
+char *memregion_dynamic_subtest_name(struct igt_collection *set);
+
+void intel_dump_gpu_meminfo(struct local_drm_i915_query_memory_regions *info);
+
+uint32_t gpu_meminfo_region_count(struct local_drm_i915_query_memory_regions *info,
+				  uint16_t region_class);
+uint64_t gpu_meminfo_region_total_size(struct local_drm_i915_query_memory_regions *info,
+				       uint16_t region_class);
+uint64_t gpu_meminfo_region_total_available(struct local_drm_i915_query_memory_regions *info,
+					    uint16_t region_type);
+
+uint64_t gpu_meminfo_region_size(struct local_drm_i915_query_memory_regions *info,
+				 uint16_t memory_class,
+				 uint16_t memory_instance);
+uint64_t gpu_meminfo_region_available(struct local_drm_i915_query_memory_regions *info,
+				      uint16_t memory_class,
+				      uint16_t memory_instance);
+
+#endif /* INTEL_MEMORY_REGION_H */
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
index 9ea67365..36640e30 100644
--- a/lib/ioctl_wrappers.h
+++ b/lib/ioctl_wrappers.h
@@ -38,6 +38,7 @@ 
 
 #include "i915/gem_context.h"
 #include "i915/gem_scheduler.h"
+#include "i915/intel_memory_region.h"
 
 /**
  * igt_ioctl:
diff --git a/lib/meson.build b/lib/meson.build
index 9929520e..7c94a7ea 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -10,6 +10,7 @@  lib_sources = [
 	'i915/gem_ring.c',
 	'i915/gem_mman.c',
 	'i915/gem_vm.c',
+	'i915/intel_memory_region.c',
 	'igt_collection.c',
 	'igt_color_encoding.c',
 	'igt_debugfs.c',