2014-07-29 11:21:10 +03:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2014 Advanced Micro Devices, Inc.
|
|
|
|
|
*
|
|
|
|
|
* 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 "fmm.h"
|
|
|
|
|
#include "linux/kfd_ioctl.h"
|
|
|
|
|
#include "libhsakmt.h"
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
2015-12-30 13:30:23 +02:00
|
|
|
#include <string.h>
|
2018-03-01 17:31:38 -05:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <unistd.h>
|
2014-07-29 11:21:10 +03:00
|
|
|
#include <inttypes.h>
|
|
|
|
|
#include <sys/mman.h>
|
2015-10-19 15:27:36 +03:00
|
|
|
#include <sys/time.h>
|
2016-03-05 01:12:40 -05:00
|
|
|
#include <errno.h>
|
2016-08-19 11:42:05 -04:00
|
|
|
#include <pci/pci.h>
|
2017-10-06 19:31:24 -04:00
|
|
|
#include <numaif.h>
|
2018-06-28 18:24:54 +08:00
|
|
|
#include "rbtree.h"
|
2017-10-06 19:31:24 -04:00
|
|
|
#ifndef MPOL_F_STATIC_NODES
|
|
|
|
|
/* Bug in numaif.h, this should be defined in there. Definition copied
|
|
|
|
|
* from linux/mempolicy.h.
|
|
|
|
|
*/
|
|
|
|
|
#define MPOL_F_STATIC_NODES (1 << 15)
|
|
|
|
|
#endif
|
2014-07-29 11:21:10 +03:00
|
|
|
|
|
|
|
|
#define NON_VALID_GPU_ID 0
|
2015-02-22 13:06:50 +02:00
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
#define INIT_MANAGEABLE_APERTURE(base_value, limit_value) { \
|
2015-02-22 13:06:50 +02:00
|
|
|
.base = (void *) base_value, \
|
|
|
|
|
.limit = (void *) limit_value, \
|
2017-04-28 16:55:52 -04:00
|
|
|
.align = 0, \
|
2017-04-05 20:54:41 -04:00
|
|
|
.guard_pages = 1, \
|
2015-02-22 13:06:50 +02:00
|
|
|
.vm_ranges = NULL, \
|
2017-06-29 12:43:14 -04:00
|
|
|
.fmm_mutex = PTHREAD_MUTEX_INITIALIZER, \
|
2018-08-04 19:45:54 -04:00
|
|
|
.is_cpu_accessible = false \
|
2015-02-22 13:06:50 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
#define container_of(ptr, type, member) ({ \
|
|
|
|
|
char *__mptr = (void *)(ptr); \
|
|
|
|
|
((type *)(__mptr - offsetof(type, member))); })
|
|
|
|
|
|
|
|
|
|
#define rb_entry(ptr, type, member) \
|
|
|
|
|
container_of(ptr, type, member)
|
|
|
|
|
|
|
|
|
|
#define vm_object_entry(n, is_userptr) ({ \
|
|
|
|
|
(is_userptr) == 0 ? \
|
|
|
|
|
rb_entry(n, vm_object_t, node) : \
|
|
|
|
|
rb_entry(n, vm_object_t, user_node); })
|
|
|
|
|
|
|
|
|
|
#define vm_object_tree(app, is_userptr) \
|
|
|
|
|
((is_userptr) ? &(app)->user_tree : &(app)->tree)
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
struct vm_object {
|
|
|
|
|
void *start;
|
2015-11-06 18:28:30 -05:00
|
|
|
void *userptr;
|
2016-09-01 23:25:42 -04:00
|
|
|
uint64_t userptr_size;
|
|
|
|
|
uint64_t size; /* size allocated on GPU. When the user requests a random
|
2017-04-20 08:25:00 -04:00
|
|
|
* size, Thunk aligns it to page size and allocates this
|
|
|
|
|
* aligned size on GPU
|
|
|
|
|
*/
|
2015-02-22 13:06:50 +02:00
|
|
|
uint64_t handle; /* opaque */
|
2016-09-01 23:25:42 -04:00
|
|
|
uint32_t node_id;
|
2018-06-28 18:24:54 +08:00
|
|
|
rbtree_node_t node;
|
|
|
|
|
rbtree_node_t user_node;
|
|
|
|
|
|
2016-01-07 16:28:20 -05:00
|
|
|
uint32_t flags; /* memory allocation flags */
|
2017-04-20 08:25:00 -04:00
|
|
|
/* Registered nodes to map on SVM mGPU */
|
2016-02-24 17:30:48 +02:00
|
|
|
uint32_t *registered_device_id_array;
|
|
|
|
|
uint32_t registered_device_id_array_size;
|
2016-09-01 23:25:42 -04:00
|
|
|
uint32_t *registered_node_id_array;
|
2017-04-20 08:25:00 -04:00
|
|
|
uint32_t registration_count; /* the same memory region can be registered multiple times */
|
|
|
|
|
/* Nodes that mapped already */
|
2016-02-24 17:30:48 +02:00
|
|
|
uint32_t *mapped_device_id_array;
|
|
|
|
|
uint32_t mapped_device_id_array_size;
|
2016-09-01 23:25:42 -04:00
|
|
|
uint32_t *mapped_node_id_array;
|
2016-11-09 14:54:17 -05:00
|
|
|
uint32_t mapping_count;
|
2016-03-05 01:12:40 -05:00
|
|
|
/* Metadata of imported graphics buffers */
|
|
|
|
|
void *metadata;
|
2016-09-01 23:25:42 -04:00
|
|
|
/* User data associated with the memory */
|
|
|
|
|
void *user_data;
|
2016-11-22 14:35:35 -05:00
|
|
|
/* Flag to indicate imported KFD buffer */
|
|
|
|
|
bool is_imported_kfd_bo;
|
2014-07-29 11:21:10 +03:00
|
|
|
};
|
|
|
|
|
typedef struct vm_object vm_object_t;
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
struct vm_area {
|
|
|
|
|
void *start;
|
|
|
|
|
void *end;
|
|
|
|
|
struct vm_area *next;
|
|
|
|
|
struct vm_area *prev;
|
2014-07-29 11:21:10 +03:00
|
|
|
};
|
|
|
|
|
typedef struct vm_area vm_area_t;
|
|
|
|
|
|
2015-11-25 18:00:42 -05:00
|
|
|
/* Memory manager for an aperture */
|
2014-07-29 11:21:10 +03:00
|
|
|
typedef struct {
|
2015-02-22 13:06:50 +02:00
|
|
|
void *base;
|
|
|
|
|
void *limit;
|
2015-10-13 19:05:39 -04:00
|
|
|
uint64_t align;
|
2017-04-05 20:54:41 -04:00
|
|
|
uint32_t guard_pages;
|
2015-02-22 13:06:50 +02:00
|
|
|
vm_area_t *vm_ranges;
|
2018-06-28 18:24:54 +08:00
|
|
|
rbtree_t tree;
|
|
|
|
|
rbtree_t user_tree;
|
2014-07-29 11:21:10 +03:00
|
|
|
pthread_mutex_t fmm_mutex;
|
2018-08-04 19:45:54 -04:00
|
|
|
bool is_cpu_accessible;
|
2017-04-20 08:25:00 -04:00
|
|
|
} manageable_aperture_t;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
|
|
|
|
typedef struct {
|
2015-02-22 13:06:50 +02:00
|
|
|
void *base;
|
|
|
|
|
void *limit;
|
2014-07-29 11:21:10 +03:00
|
|
|
} aperture_t;
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
typedef struct {
|
2014-10-13 11:29:39 +03:00
|
|
|
uint32_t gpu_id;
|
2015-10-15 12:03:31 -04:00
|
|
|
uint32_t device_id;
|
|
|
|
|
uint32_t node_id;
|
|
|
|
|
uint64_t local_mem_size;
|
2014-07-29 11:21:10 +03:00
|
|
|
aperture_t lds_aperture;
|
2018-08-04 16:56:15 -04:00
|
|
|
aperture_t scratch_aperture;
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t scratch_physical; /* For dGPU, scratch physical is allocated from
|
|
|
|
|
* dgpu_aperture. When requested by RT, each
|
|
|
|
|
* GPU will get a differnt range
|
|
|
|
|
*/
|
|
|
|
|
manageable_aperture_t gpuvm_aperture; /* used for GPUVM on APU, outsidethe canonical address range */
|
2018-03-01 17:31:38 -05:00
|
|
|
int drm_render_fd;
|
2015-02-22 13:06:50 +02:00
|
|
|
} gpu_mem_t;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
enum svm_aperture_type {
|
|
|
|
|
SVM_DEFAULT = 0,
|
|
|
|
|
SVM_COHERENT,
|
|
|
|
|
SVM_APERTURE_NUM
|
|
|
|
|
};
|
|
|
|
|
|
2016-03-01 17:50:46 -05:00
|
|
|
/* The main structure for dGPU Shared Virtual Memory Management */
|
2015-11-25 18:00:42 -05:00
|
|
|
typedef struct {
|
2018-08-10 17:05:42 -04:00
|
|
|
/* Two apertures can have different MTypes (for coherency) */
|
|
|
|
|
manageable_aperture_t apertures[SVM_APERTURE_NUM];
|
2015-11-25 18:00:42 -05:00
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
/* Pointers to apertures, may point to the same aperture on
|
|
|
|
|
* GFXv9 and later, where MType is not based on apertures
|
2017-04-20 08:25:00 -04:00
|
|
|
*/
|
2018-08-10 17:05:42 -04:00
|
|
|
manageable_aperture_t *dgpu_aperture;
|
|
|
|
|
manageable_aperture_t *dgpu_alt_aperture;
|
2016-02-03 18:24:38 -05:00
|
|
|
|
|
|
|
|
/* whether to use userptr for paged memory */
|
|
|
|
|
bool userptr_for_paged_mem;
|
2017-04-05 17:22:36 -04:00
|
|
|
|
|
|
|
|
/* whether to check userptrs on registration */
|
|
|
|
|
bool check_userptr;
|
2018-08-10 17:05:42 -04:00
|
|
|
|
|
|
|
|
/* whether all memory is coherent (GPU cache disabled) */
|
|
|
|
|
bool disable_cache;
|
2015-11-25 18:00:42 -05:00
|
|
|
} svm_t;
|
|
|
|
|
|
|
|
|
|
/* The other apertures are specific to each GPU. gpu_mem_t manages GPU
|
2017-04-20 08:25:00 -04:00
|
|
|
* specific memory apertures.
|
|
|
|
|
*/
|
2016-01-13 17:27:31 -05:00
|
|
|
static gpu_mem_t *gpu_mem;
|
|
|
|
|
static unsigned int gpu_mem_count;
|
2018-08-03 03:01:22 -04:00
|
|
|
static gpu_mem_t *g_first_gpu_mem;
|
|
|
|
|
|
2017-12-08 15:59:01 -05:00
|
|
|
static bool hsa_debug;
|
2017-04-20 08:25:00 -04:00
|
|
|
static void *dgpu_shared_aperture_base;
|
|
|
|
|
static void *dgpu_shared_aperture_limit;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2015-11-25 18:00:42 -05:00
|
|
|
static svm_t svm = {
|
2018-08-10 17:05:42 -04:00
|
|
|
.apertures = {INIT_MANAGEABLE_APERTURE(0, 0),
|
|
|
|
|
INIT_MANAGEABLE_APERTURE(0, 0)},
|
|
|
|
|
.dgpu_aperture = NULL,
|
|
|
|
|
.dgpu_alt_aperture = NULL,
|
|
|
|
|
.userptr_for_paged_mem = false,
|
|
|
|
|
.check_userptr = false,
|
|
|
|
|
.disable_cache = false
|
2015-11-25 18:00:42 -05:00
|
|
|
};
|
|
|
|
|
|
2016-09-08 15:01:28 -04:00
|
|
|
/* On APU, for memory allocated on the system memory that GPU doesn't access
|
|
|
|
|
* via GPU driver, they are not managed by GPUVM. cpuvm_aperture keeps track
|
|
|
|
|
* of this part of memory.
|
|
|
|
|
*/
|
2017-04-20 08:25:00 -04:00
|
|
|
static manageable_aperture_t cpuvm_aperture = INIT_MANAGEABLE_APERTURE(0, 0);
|
2016-09-08 15:01:28 -04:00
|
|
|
|
2016-01-07 16:28:20 -05:00
|
|
|
/* GPU node array for default mappings */
|
2017-04-20 08:25:00 -04:00
|
|
|
static uint32_t all_gpu_id_array_size;
|
|
|
|
|
static uint32_t *all_gpu_id_array;
|
2016-01-07 16:28:20 -05:00
|
|
|
|
2016-11-22 14:35:35 -05:00
|
|
|
/* IPC structures and helper functions */
|
|
|
|
|
typedef enum _HSA_APERTURE {
|
|
|
|
|
HSA_APERTURE_UNSUPPORTED = 0,
|
|
|
|
|
HSA_APERTURE_DGPU,
|
|
|
|
|
HSA_APERTURE_DGPU_ALT,
|
|
|
|
|
HSA_APERTURE_GPUVM,
|
|
|
|
|
HSA_APERTURE_CPUVM
|
|
|
|
|
} HSA_APERTURE;
|
|
|
|
|
|
|
|
|
|
typedef struct _HsaApertureInfo {
|
|
|
|
|
HSA_APERTURE type; // Aperture type
|
|
|
|
|
HSAuint32 idx; // Aperture index
|
|
|
|
|
} HsaApertureInfo;
|
|
|
|
|
|
|
|
|
|
typedef struct _HsaSharedMemoryStruct {
|
|
|
|
|
HSAuint32 ShareHandle[4];
|
|
|
|
|
HsaApertureInfo ApeInfo;
|
|
|
|
|
HSAuint32 SizeInPages;
|
|
|
|
|
HSAuint32 ExportGpuId;
|
|
|
|
|
} HsaSharedMemoryStruct;
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static inline const HsaSharedMemoryStruct *to_const_hsa_shared_memory_struct(
|
2016-11-22 14:35:35 -05:00
|
|
|
const HsaSharedMemoryHandle *SharedMemoryHandle)
|
|
|
|
|
{
|
|
|
|
|
return (const HsaSharedMemoryStruct *)SharedMemoryHandle;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static inline HsaSharedMemoryStruct *to_hsa_shared_memory_struct(
|
2016-11-22 14:35:35 -05:00
|
|
|
HsaSharedMemoryHandle *SharedMemoryHandle)
|
|
|
|
|
{
|
|
|
|
|
return (HsaSharedMemoryStruct *)SharedMemoryHandle;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static inline HsaSharedMemoryHandle *to_hsa_shared_memory_handle(
|
2016-11-22 14:35:35 -05:00
|
|
|
HsaSharedMemoryStruct *SharedMemoryStruct)
|
|
|
|
|
{
|
|
|
|
|
return (HsaSharedMemoryHandle *)SharedMemoryStruct;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
extern int debug_get_reg_status(uint32_t node_id, bool *is_debugged);
|
2018-06-20 13:30:06 +08:00
|
|
|
static void __fmm_release(vm_object_t *object, manageable_aperture_t *aperture);
|
2015-10-17 02:50:50 -04:00
|
|
|
static int _fmm_unmap_from_gpu_scratch(uint32_t gpu_id,
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture,
|
2015-10-17 02:50:50 -04:00
|
|
|
void *address);
|
2016-02-24 17:30:48 +02:00
|
|
|
static void print_device_id_array(uint32_t *device_id_array, uint32_t device_id_array_size);
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
static vm_area_t *vm_create_and_init_area(void *start, void *end)
|
|
|
|
|
{
|
|
|
|
|
vm_area_t *area = (vm_area_t *) malloc(sizeof(vm_area_t));
|
|
|
|
|
|
|
|
|
|
if (area) {
|
2014-07-29 11:21:10 +03:00
|
|
|
area->start = start;
|
|
|
|
|
area->end = end;
|
|
|
|
|
area->next = area->prev = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return area;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
static vm_object_t *vm_create_and_init_object(void *start, uint64_t size,
|
2016-01-07 16:28:20 -05:00
|
|
|
uint64_t handle, uint32_t flags)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
|
|
|
|
vm_object_t *object = (vm_object_t *) malloc(sizeof(vm_object_t));
|
|
|
|
|
|
|
|
|
|
if (object) {
|
2014-07-29 11:21:10 +03:00
|
|
|
object->start = start;
|
2015-11-06 18:28:30 -05:00
|
|
|
object->userptr = NULL;
|
2016-09-01 23:25:42 -04:00
|
|
|
object->userptr_size = 0;
|
2014-07-29 11:21:10 +03:00
|
|
|
object->size = size;
|
|
|
|
|
object->handle = handle;
|
2016-02-24 17:30:48 +02:00
|
|
|
object->registered_device_id_array_size = 0;
|
|
|
|
|
object->mapped_device_id_array_size = 0;
|
2017-11-30 10:56:38 -05:00
|
|
|
object->registered_device_id_array = NULL;
|
|
|
|
|
object->mapped_device_id_array = NULL;
|
2016-09-01 23:25:42 -04:00
|
|
|
object->registered_node_id_array = NULL;
|
|
|
|
|
object->mapped_node_id_array = NULL;
|
2016-11-09 14:54:17 -05:00
|
|
|
object->registration_count = 0;
|
|
|
|
|
object->mapping_count = 0;
|
2016-01-07 16:28:20 -05:00
|
|
|
object->flags = flags;
|
2016-03-05 01:12:40 -05:00
|
|
|
object->metadata = NULL;
|
2016-11-09 21:15:07 -06:00
|
|
|
object->user_data = NULL;
|
2016-11-22 14:35:35 -05:00
|
|
|
object->is_imported_kfd_bo = false;
|
2018-06-28 18:24:54 +08:00
|
|
|
object->node.key = rbtree_key((unsigned long)start, size);
|
|
|
|
|
object->user_node.key = rbtree_key(0, 0);
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static void vm_remove_area(manageable_aperture_t *app, vm_area_t *area)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
|
|
|
|
vm_area_t *next;
|
|
|
|
|
vm_area_t *prev;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
|
|
|
|
next = area->next;
|
|
|
|
|
prev = area->prev;
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!prev) /* The first element */
|
2014-07-29 11:21:10 +03:00
|
|
|
app->vm_ranges = next;
|
|
|
|
|
else
|
|
|
|
|
prev->next = next;
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
if (next) /* If not the last element */
|
2014-07-29 11:21:10 +03:00
|
|
|
next->prev = prev;
|
|
|
|
|
|
|
|
|
|
free(area);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static void vm_remove_object(manageable_aperture_t *app, vm_object_t *object)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
2016-09-08 15:01:28 -04:00
|
|
|
/* Free allocations inside the object */
|
2017-11-30 10:56:38 -05:00
|
|
|
if (object->registered_device_id_array)
|
2016-09-08 15:01:28 -04:00
|
|
|
free(object->registered_device_id_array);
|
2017-11-30 10:56:38 -05:00
|
|
|
|
|
|
|
|
if (object->mapped_device_id_array)
|
2016-09-08 15:01:28 -04:00
|
|
|
free(object->mapped_device_id_array);
|
2017-11-30 10:56:38 -05:00
|
|
|
|
2016-09-08 15:01:28 -04:00
|
|
|
if (object->metadata)
|
|
|
|
|
free(object->metadata);
|
|
|
|
|
|
|
|
|
|
if (object->registered_node_id_array)
|
|
|
|
|
free(object->registered_node_id_array);
|
|
|
|
|
if (object->mapped_node_id_array)
|
|
|
|
|
free(object->mapped_node_id_array);
|
|
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
rbtree_delete(&app->tree, &object->node);
|
|
|
|
|
if (object->userptr)
|
|
|
|
|
rbtree_delete(&app->user_tree, &object->user_node);
|
2014-07-29 11:21:10 +03:00
|
|
|
|
|
|
|
|
free(object);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
static void vm_add_area_after(vm_area_t *after_this, vm_area_t *new_area)
|
|
|
|
|
{
|
|
|
|
|
vm_area_t *next = after_this->next;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
|
|
|
|
after_this->next = new_area;
|
|
|
|
|
new_area->next = next;
|
|
|
|
|
|
|
|
|
|
new_area->prev = after_this;
|
|
|
|
|
if (next)
|
|
|
|
|
next->prev = new_area;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static void vm_split_area(manageable_aperture_t *app, vm_area_t *area,
|
2015-02-22 13:06:50 +02:00
|
|
|
void *address, uint64_t MemorySizeInBytes)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The existing area is split to: [area->start, address - 1]
|
|
|
|
|
* and [address + MemorySizeInBytes, area->end]
|
|
|
|
|
*/
|
|
|
|
|
vm_area_t *new_area = vm_create_and_init_area(
|
|
|
|
|
VOID_PTR_ADD(address, MemorySizeInBytes),
|
|
|
|
|
area->end);
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/* Shrink the existing area */
|
|
|
|
|
area->end = VOID_PTR_SUB(address, 1);
|
2014-07-29 11:21:10 +03:00
|
|
|
|
|
|
|
|
vm_add_area_after(area, new_area);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
static vm_object_t *vm_find_object_by_address_userptr(manageable_aperture_t *app,
|
|
|
|
|
const void *address, uint64_t size, int is_userptr)
|
2016-09-13 12:44:29 -04:00
|
|
|
{
|
2018-06-28 18:24:54 +08:00
|
|
|
vm_object_t *cur = NULL;
|
2016-09-13 12:44:29 -04:00
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
if (is_userptr == 0)
|
|
|
|
|
size = ALIGN_UP(size, app->align);
|
|
|
|
|
rbtree_t *tree = vm_object_tree(app, is_userptr);
|
|
|
|
|
rbtree_key_t key = rbtree_key((unsigned long)address, size);
|
|
|
|
|
void *start;
|
|
|
|
|
uint64_t s;
|
2016-09-13 12:44:29 -04:00
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
/* rbtree_lookup_nearest(,,,RIGHT) will return a node with
|
|
|
|
|
* its size >= key.size and its address >= key.address
|
|
|
|
|
* if there are two nodes with format(address, size),
|
|
|
|
|
* (0x100, 16) and (0x110, 8). the key is (0x100, 0),
|
|
|
|
|
* then node (0x100, 16) will be returned.
|
|
|
|
|
*/
|
|
|
|
|
rbtree_node_t *n = rbtree_lookup_nearest(tree, &key, LKP_ALL, RIGHT);
|
|
|
|
|
|
|
|
|
|
if (n) {
|
|
|
|
|
cur = vm_object_entry(n, is_userptr);
|
|
|
|
|
if (is_userptr == 0) {
|
|
|
|
|
start = cur->start;
|
|
|
|
|
s = cur->size;
|
|
|
|
|
} else {
|
|
|
|
|
start = cur->userptr;
|
|
|
|
|
s = cur->userptr_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (start != address)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (size)
|
|
|
|
|
return size == s ? cur : NULL;
|
|
|
|
|
|
|
|
|
|
/* size is 0, make sure there is only one node whose address == key.address*/
|
|
|
|
|
key = rbtree_key((unsigned long)address, (unsigned long)-1);
|
|
|
|
|
rbtree_node_t *rn = rbtree_lookup_nearest(tree, &key, LKP_ALL, LEFT);
|
|
|
|
|
|
|
|
|
|
if (rn != n)
|
|
|
|
|
return NULL;
|
2016-09-13 12:44:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cur; /* NULL if not found */
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
|
|
|
|
|
static vm_object_t *vm_find_object_by_address_userptr_range(manageable_aperture_t *app,
|
|
|
|
|
const void *address, int is_userptr)
|
2016-09-01 23:25:42 -04:00
|
|
|
{
|
2018-06-28 18:24:54 +08:00
|
|
|
vm_object_t *cur = NULL;
|
|
|
|
|
rbtree_t *tree = vm_object_tree(app, is_userptr);
|
|
|
|
|
rbtree_key_t key = rbtree_key((unsigned long)address, 0);
|
|
|
|
|
rbtree_node_t *ln = rbtree_lookup_nearest(tree, &key,
|
|
|
|
|
LKP_ALL, LEFT);
|
|
|
|
|
rbtree_node_t *rn = rbtree_lookup_nearest(tree, &key,
|
|
|
|
|
LKP_ALL, RIGHT);
|
|
|
|
|
void *start;
|
|
|
|
|
uint64_t size;
|
|
|
|
|
int bad = 0;
|
|
|
|
|
|
|
|
|
|
loop:
|
|
|
|
|
while (ln) {
|
|
|
|
|
cur = vm_object_entry(ln, is_userptr);
|
|
|
|
|
if (is_userptr == 0) {
|
|
|
|
|
start = cur->start;
|
|
|
|
|
size = cur->size;
|
|
|
|
|
} else {
|
|
|
|
|
start = cur->userptr;
|
|
|
|
|
size = cur->userptr_size;
|
|
|
|
|
}
|
2016-09-01 23:25:42 -04:00
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
if (address >= start &&
|
|
|
|
|
(uint64_t)address < ((uint64_t)start + size))
|
2016-09-01 23:25:42 -04:00
|
|
|
break;
|
2018-06-28 18:24:54 +08:00
|
|
|
|
|
|
|
|
cur = NULL;
|
|
|
|
|
|
|
|
|
|
if (ln == rn)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
ln = rbtree_next(tree, ln);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cur == NULL && bad == 0) {
|
|
|
|
|
/* As there is area overlap, say, (address, size) like
|
|
|
|
|
* (0x100, 32), (0x108, 8), and the key.address is 0x118
|
|
|
|
|
* The lookup above only find (0x108, 8), but the correct node should
|
|
|
|
|
* be (0x100, 16). So try to walk though the tree to find the node.
|
|
|
|
|
*/
|
|
|
|
|
rn = ln;
|
|
|
|
|
key = rbtree_key(0, 0);
|
|
|
|
|
ln = rbtree_lookup_nearest(tree, &key, LKP_ALL, RIGHT);
|
|
|
|
|
bad = 1;
|
|
|
|
|
goto loop;
|
2016-09-01 23:25:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cur; /* NULL if not found */
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
static vm_object_t *vm_find_object_by_address(manageable_aperture_t *app,
|
|
|
|
|
const void *address, uint64_t size)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
2018-06-28 18:24:54 +08:00
|
|
|
return vm_find_object_by_address_userptr(app, address, size, 0);
|
|
|
|
|
}
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
static vm_object_t *vm_find_object_by_address_range(manageable_aperture_t *app,
|
|
|
|
|
const void *address)
|
|
|
|
|
{
|
|
|
|
|
return vm_find_object_by_address_userptr_range(app, address, 0);
|
|
|
|
|
}
|
2016-11-09 14:54:17 -05:00
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
static vm_object_t *vm_find_object_by_userptr(manageable_aperture_t *app,
|
|
|
|
|
const void *address, HSAuint64 size)
|
|
|
|
|
{
|
|
|
|
|
return vm_find_object_by_address_userptr(app, address, size, 1);
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static vm_object_t *vm_find_object_by_userptr_range(manageable_aperture_t *app,
|
2016-09-01 23:25:42 -04:00
|
|
|
const void *address)
|
2015-11-06 18:28:30 -05:00
|
|
|
{
|
2018-06-28 18:24:54 +08:00
|
|
|
return vm_find_object_by_address_userptr_range(app, address, 1);
|
2015-11-06 18:28:30 -05:00
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static vm_area_t *vm_find(manageable_aperture_t *app, void *address)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
|
|
|
|
vm_area_t *cur = app->vm_ranges;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/* Look up the appropriate address range containing the given address */
|
|
|
|
|
while (cur) {
|
|
|
|
|
if (cur->start <= address && cur->end >= address)
|
2014-07-29 11:21:10 +03:00
|
|
|
break;
|
|
|
|
|
cur = cur->next;
|
|
|
|
|
};
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
return cur; /* NULL if not found */
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
static bool aperture_is_valid(void *app_base, void *app_limit)
|
|
|
|
|
{
|
2014-07-29 11:21:10 +03:00
|
|
|
if (app_base && app_limit && app_base < app_limit)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-30 11:26:22 -04:00
|
|
|
/* Align size of a VM area
|
|
|
|
|
*
|
|
|
|
|
* Leave at least one guard page after every object to catch
|
|
|
|
|
* out-of-bounds accesses with VM faults.
|
|
|
|
|
*/
|
2017-04-20 08:25:00 -04:00
|
|
|
static uint64_t vm_align_area_size(manageable_aperture_t *app, uint64_t size)
|
2017-03-30 11:26:22 -04:00
|
|
|
{
|
2018-08-09 17:41:03 +08:00
|
|
|
return ALIGN_UP(ALIGN_UP(size, app->align) + (uint64_t)app->guard_pages * PAGE_SIZE,
|
2017-04-05 20:54:41 -04:00
|
|
|
app->align);
|
2017-03-30 11:26:22 -04:00
|
|
|
}
|
|
|
|
|
|
2014-07-29 11:21:10 +03:00
|
|
|
/*
|
|
|
|
|
* Assumes that fmm_mutex is locked on entry.
|
|
|
|
|
*/
|
2017-04-20 08:25:00 -04:00
|
|
|
static void aperture_release_area(manageable_aperture_t *app, void *address,
|
2015-02-22 13:06:50 +02:00
|
|
|
uint64_t MemorySizeInBytes)
|
|
|
|
|
{
|
|
|
|
|
vm_area_t *area;
|
|
|
|
|
uint64_t SizeOfRegion;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2017-03-30 11:26:22 -04:00
|
|
|
MemorySizeInBytes = vm_align_area_size(app, MemorySizeInBytes);
|
2015-10-13 19:05:39 -04:00
|
|
|
|
2014-07-29 11:21:10 +03:00
|
|
|
area = vm_find(app, address);
|
2015-02-22 13:06:50 +02:00
|
|
|
if (!area)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
SizeOfRegion = VOID_PTRS_SUB(area->end, area->start) + 1;
|
|
|
|
|
|
|
|
|
|
/* check if block is whole region or part of it */
|
|
|
|
|
if (SizeOfRegion == MemorySizeInBytes) {
|
|
|
|
|
vm_remove_area(app, area);
|
|
|
|
|
} else if (SizeOfRegion > MemorySizeInBytes) {
|
|
|
|
|
/* shrink from the start */
|
|
|
|
|
if (area->start == address)
|
|
|
|
|
area->start =
|
|
|
|
|
VOID_PTR_ADD(area->start, MemorySizeInBytes);
|
|
|
|
|
/* shrink from the end */
|
|
|
|
|
else if (VOID_PTRS_SUB(area->end, address) + 1 ==
|
|
|
|
|
MemorySizeInBytes)
|
|
|
|
|
area->end = VOID_PTR_SUB(area->end, MemorySizeInBytes);
|
|
|
|
|
/* split the area */
|
|
|
|
|
else
|
|
|
|
|
vm_split_area(app, area, address, MemorySizeInBytes);
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
2018-08-04 19:45:54 -04:00
|
|
|
|
|
|
|
|
if (app->is_cpu_accessible) {
|
|
|
|
|
void *mmap_ret;
|
|
|
|
|
|
|
|
|
|
/* Reset NUMA policy */
|
|
|
|
|
mbind(address, MemorySizeInBytes, MPOL_DEFAULT, NULL, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* Remove any CPU mapping, but keep the address range reserved */
|
|
|
|
|
mmap_ret = mmap(address, MemorySizeInBytes, PROT_NONE,
|
|
|
|
|
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED,
|
|
|
|
|
-1, 0);
|
|
|
|
|
if (mmap_ret == MAP_FAILED && errno == ENOMEM) {
|
|
|
|
|
/* When mmap count reaches max_map_count, any mmap will
|
|
|
|
|
* fail. Reduce the count with munmap then map it as
|
|
|
|
|
* NORESERVE immediately.
|
|
|
|
|
*/
|
|
|
|
|
munmap(address, MemorySizeInBytes);
|
|
|
|
|
mmap(address, MemorySizeInBytes, PROT_NONE,
|
|
|
|
|
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED,
|
|
|
|
|
-1, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2015-02-22 13:06:50 +02:00
|
|
|
* returns allocated address or NULL. Assumes, that fmm_mutex is locked
|
|
|
|
|
* on entry.
|
2014-07-29 11:21:10 +03:00
|
|
|
*/
|
2017-04-20 08:25:00 -04:00
|
|
|
static void *aperture_allocate_area_aligned(manageable_aperture_t *app,
|
2015-10-17 02:48:23 -04:00
|
|
|
uint64_t MemorySizeInBytes,
|
|
|
|
|
uint64_t align)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
2015-10-17 02:48:23 -04:00
|
|
|
vm_area_t *cur, *next;
|
|
|
|
|
void *start;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2015-10-17 02:48:23 -04:00
|
|
|
if (align < app->align)
|
|
|
|
|
align = app->align;
|
|
|
|
|
|
2017-08-28 14:57:20 -04:00
|
|
|
/* Align big buffers to the next power-of-2 up to huge page
|
|
|
|
|
* size for flexible fragment size TLB optimizations
|
|
|
|
|
*/
|
|
|
|
|
while (align < GPU_HUGE_PAGE_SIZE && MemorySizeInBytes >= (align << 1))
|
|
|
|
|
align <<= 1;
|
2017-06-29 14:33:08 -04:00
|
|
|
|
|
|
|
|
MemorySizeInBytes = vm_align_area_size(app, MemorySizeInBytes);
|
|
|
|
|
|
2015-10-17 02:48:23 -04:00
|
|
|
/* Find a big enough "hole" in the address space */
|
|
|
|
|
cur = NULL;
|
|
|
|
|
next = app->vm_ranges;
|
2018-08-04 15:58:23 -04:00
|
|
|
start = (void *)ALIGN_UP((uint64_t)app->base, align);
|
2015-10-17 02:48:23 -04:00
|
|
|
while (next) {
|
|
|
|
|
if (next->start > start &&
|
|
|
|
|
VOID_PTRS_SUB(next->start, start) >= MemorySizeInBytes)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
cur = next;
|
|
|
|
|
next = next->next;
|
|
|
|
|
start = (void *)ALIGN_UP((uint64_t)cur->end + 1, align);
|
|
|
|
|
}
|
|
|
|
|
if (!next && VOID_PTRS_SUB(app->limit, start) + 1 < MemorySizeInBytes)
|
|
|
|
|
/* No hole found and not enough space after the last area */
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (cur && VOID_PTR_ADD(cur->end, 1) == start) {
|
|
|
|
|
/* extend existing area */
|
|
|
|
|
cur->end = VOID_PTR_ADD(start, MemorySizeInBytes-1);
|
|
|
|
|
} else {
|
|
|
|
|
vm_area_t *new_area;
|
|
|
|
|
/* create a new area between cur and next */
|
2015-02-22 13:06:50 +02:00
|
|
|
new_area = vm_create_and_init_area(start,
|
|
|
|
|
VOID_PTR_ADD(start, (MemorySizeInBytes - 1)));
|
2015-10-17 02:48:23 -04:00
|
|
|
if (!new_area)
|
|
|
|
|
return NULL;
|
|
|
|
|
new_area->next = next;
|
|
|
|
|
new_area->prev = cur;
|
|
|
|
|
if (cur)
|
|
|
|
|
cur->next = new_area;
|
|
|
|
|
else
|
2014-07-29 11:21:10 +03:00
|
|
|
app->vm_ranges = new_area;
|
2015-10-17 02:48:23 -04:00
|
|
|
if (next)
|
|
|
|
|
next->prev = new_area;
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2015-10-17 02:48:23 -04:00
|
|
|
return start;
|
|
|
|
|
}
|
2017-04-20 08:25:00 -04:00
|
|
|
static void *aperture_allocate_area(manageable_aperture_t *app,
|
2018-08-04 15:58:23 -04:00
|
|
|
uint64_t MemorySizeInBytes)
|
2015-10-17 02:48:23 -04:00
|
|
|
{
|
2018-08-04 15:58:23 -04:00
|
|
|
return aperture_allocate_area_aligned(app, MemorySizeInBytes, app->align);
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/* returns 0 on success. Assumes, that fmm_mutex is locked on entry */
|
2017-04-20 08:25:00 -04:00
|
|
|
static vm_object_t *aperture_allocate_object(manageable_aperture_t *app,
|
2016-03-05 01:12:40 -05:00
|
|
|
void *new_address,
|
|
|
|
|
uint64_t handle,
|
|
|
|
|
uint64_t MemorySizeInBytes,
|
|
|
|
|
uint32_t flags)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
|
|
|
|
vm_object_t *new_object;
|
|
|
|
|
|
2015-10-13 19:05:39 -04:00
|
|
|
MemorySizeInBytes = ALIGN_UP(MemorySizeInBytes, app->align);
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/* Allocate new object */
|
|
|
|
|
new_object = vm_create_and_init_object(new_address,
|
2016-01-07 16:28:20 -05:00
|
|
|
MemorySizeInBytes,
|
|
|
|
|
handle, flags);
|
2015-02-22 13:06:50 +02:00
|
|
|
if (!new_object)
|
2016-03-05 01:12:40 -05:00
|
|
|
return NULL;
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
rbtree_insert(&app->tree, &new_object->node);
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2016-03-05 01:12:40 -05:00
|
|
|
return new_object;
|
2014-10-13 11:29:39 +03:00
|
|
|
}
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
static int32_t gpu_mem_find_by_gpu_id(uint32_t gpu_id)
|
|
|
|
|
{
|
2016-01-13 17:27:31 -05:00
|
|
|
uint32_t i;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2016-01-13 17:27:31 -05:00
|
|
|
for (i = 0 ; i < gpu_mem_count ; i++)
|
2015-02-22 13:06:50 +02:00
|
|
|
if (gpu_mem[i].gpu_id == gpu_id)
|
2014-07-29 11:21:10 +03:00
|
|
|
return i;
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static manageable_aperture_t *fmm_get_aperture(HsaApertureInfo info)
|
2016-11-22 14:35:35 -05:00
|
|
|
{
|
|
|
|
|
switch (info.type) {
|
2017-04-20 08:25:00 -04:00
|
|
|
case HSA_APERTURE_DGPU:
|
2018-08-10 17:05:42 -04:00
|
|
|
return svm.dgpu_aperture;
|
2017-04-20 08:25:00 -04:00
|
|
|
case HSA_APERTURE_DGPU_ALT:
|
2018-08-10 17:05:42 -04:00
|
|
|
return svm.dgpu_alt_aperture;
|
2017-04-20 08:25:00 -04:00
|
|
|
case HSA_APERTURE_GPUVM:
|
|
|
|
|
return &gpu_mem[info.idx].gpuvm_aperture;
|
|
|
|
|
case HSA_APERTURE_CPUVM:
|
|
|
|
|
return &cpuvm_aperture;
|
|
|
|
|
default:
|
|
|
|
|
return NULL;
|
2016-11-22 14:35:35 -05:00
|
|
|
}
|
|
|
|
|
}
|
2017-08-18 16:50:54 -04:00
|
|
|
|
|
|
|
|
static manageable_aperture_t *fmm_is_scratch_aperture(const void *address)
|
|
|
|
|
{
|
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < gpu_mem_count; i++) {
|
|
|
|
|
if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if ((address >= gpu_mem[i].scratch_physical.base) &&
|
|
|
|
|
(address <= gpu_mem[i].scratch_physical.limit))
|
|
|
|
|
return &gpu_mem[i].scratch_physical;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static manageable_aperture_t *fmm_find_aperture(const void *address,
|
2016-11-22 14:35:35 -05:00
|
|
|
HsaApertureInfo *info)
|
2016-09-08 15:01:28 -04:00
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture = NULL;
|
2016-09-08 15:01:28 -04:00
|
|
|
uint32_t i;
|
2016-11-22 14:35:35 -05:00
|
|
|
HsaApertureInfo _info = { .type = HSA_APERTURE_UNSUPPORTED, .idx = 0};
|
2016-09-08 15:01:28 -04:00
|
|
|
|
|
|
|
|
if (is_dgpu) {
|
2018-08-10 17:05:42 -04:00
|
|
|
if (address >= svm.dgpu_aperture->base &&
|
|
|
|
|
address <= svm.dgpu_aperture->limit) {
|
2017-08-18 16:50:54 -04:00
|
|
|
|
|
|
|
|
aperture = fmm_is_scratch_aperture(address);
|
|
|
|
|
if (!aperture) {
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2017-08-18 16:50:54 -04:00
|
|
|
_info.type = HSA_APERTURE_DGPU;
|
|
|
|
|
}
|
2018-08-10 17:05:42 -04:00
|
|
|
} else if (address >= svm.dgpu_alt_aperture->base &&
|
|
|
|
|
address <= svm.dgpu_alt_aperture->limit) {
|
|
|
|
|
aperture = svm.dgpu_alt_aperture;
|
2016-11-22 14:35:35 -05:00
|
|
|
_info.type = HSA_APERTURE_DGPU_ALT;
|
2017-04-20 08:25:00 -04:00
|
|
|
} else {
|
2016-11-22 14:35:35 -05:00
|
|
|
/* Not in SVM, it can be system memory registered by userptr */
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2016-11-22 14:35:35 -05:00
|
|
|
_info.type = HSA_APERTURE_DGPU;
|
|
|
|
|
}
|
2017-04-20 08:25:00 -04:00
|
|
|
} else { /* APU */
|
2018-08-10 17:05:42 -04:00
|
|
|
if (address >= svm.dgpu_aperture->base && address <= svm.dgpu_aperture->limit) {
|
|
|
|
|
aperture = svm.dgpu_aperture;
|
2017-09-27 16:53:57 -04:00
|
|
|
_info.type = HSA_APERTURE_DGPU;
|
|
|
|
|
} else {
|
|
|
|
|
/* gpuvm_aperture */
|
|
|
|
|
for (i = 0; i < gpu_mem_count; i++) {
|
|
|
|
|
if ((address >= gpu_mem[i].gpuvm_aperture.base) &&
|
|
|
|
|
(address <= gpu_mem[i].gpuvm_aperture.limit)) {
|
|
|
|
|
aperture = &gpu_mem[i].gpuvm_aperture;
|
|
|
|
|
_info.type = HSA_APERTURE_GPUVM;
|
|
|
|
|
_info.idx = i;
|
|
|
|
|
}
|
2016-11-22 14:35:35 -05:00
|
|
|
}
|
2016-09-08 15:01:28 -04:00
|
|
|
}
|
2016-11-22 14:35:35 -05:00
|
|
|
if (!aperture) {
|
|
|
|
|
/* Not in GPUVM */
|
2016-09-08 15:01:28 -04:00
|
|
|
aperture = &cpuvm_aperture;
|
2016-11-22 14:35:35 -05:00
|
|
|
_info.type = HSA_APERTURE_CPUVM;
|
|
|
|
|
}
|
2016-09-08 15:01:28 -04:00
|
|
|
}
|
|
|
|
|
|
2016-11-22 14:35:35 -05:00
|
|
|
if (info)
|
|
|
|
|
*info = _info;
|
|
|
|
|
|
2016-09-08 15:01:28 -04:00
|
|
|
return aperture;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-01 23:25:42 -04:00
|
|
|
/* After allocating the memory, return the vm_object created for this memory.
|
|
|
|
|
* Return NULL if any failure.
|
|
|
|
|
*/
|
2017-12-04 10:23:55 -05:00
|
|
|
static vm_object_t *fmm_allocate_memory_object(uint32_t gpu_id, void *mem,
|
2015-08-23 17:42:27 +03:00
|
|
|
uint64_t MemorySizeInBytes,
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture,
|
2015-09-09 14:41:28 +03:00
|
|
|
uint64_t *mmap_offset,
|
|
|
|
|
uint32_t flags)
|
2015-02-23 15:54:01 +02:00
|
|
|
{
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_alloc_memory_of_gpu_args args = {0};
|
|
|
|
|
struct kfd_ioctl_free_memory_of_gpu_args free_args = {0};
|
2016-09-01 23:25:42 -04:00
|
|
|
vm_object_t *vm_obj = NULL;
|
2015-02-23 15:54:01 +02:00
|
|
|
|
|
|
|
|
if (!mem)
|
2016-09-01 23:25:42 -04:00
|
|
|
return NULL;
|
2015-02-23 15:54:01 +02:00
|
|
|
|
|
|
|
|
/* Allocate memory from amdkfd */
|
|
|
|
|
args.gpu_id = gpu_id;
|
2015-10-13 19:05:39 -04:00
|
|
|
args.size = ALIGN_UP(MemorySizeInBytes, aperture->align);
|
2015-02-23 15:54:01 +02:00
|
|
|
|
2017-05-01 19:19:38 -04:00
|
|
|
args.flags = flags |
|
|
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE;
|
2015-08-23 17:42:27 +03:00
|
|
|
args.va_addr = (uint64_t)mem;
|
2017-05-01 19:19:38 -04:00
|
|
|
if (!topology_is_dgpu(get_device_id_by_gpu_id(gpu_id)) &&
|
|
|
|
|
(flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM))
|
2015-08-23 17:42:27 +03:00
|
|
|
args.va_addr = VOID_PTRS_SUB(mem, aperture->base);
|
2015-11-06 18:28:30 -05:00
|
|
|
if (flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR)
|
|
|
|
|
args.mmap_offset = *mmap_offset;
|
2015-02-23 15:54:01 +02:00
|
|
|
|
2017-05-01 19:19:38 -04:00
|
|
|
if (kmtIoctl(kfd_fd, AMDKFD_IOC_ALLOC_MEMORY_OF_GPU, &args))
|
2016-09-01 23:25:42 -04:00
|
|
|
return NULL;
|
2015-02-23 15:54:01 +02:00
|
|
|
|
|
|
|
|
/* Allocate object */
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2017-04-20 08:25:00 -04:00
|
|
|
vm_obj = aperture_allocate_object(aperture, mem, args.handle,
|
|
|
|
|
MemorySizeInBytes, flags);
|
|
|
|
|
if (!vm_obj)
|
2015-02-23 15:54:01 +02:00
|
|
|
goto err_object_allocation_failed;
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
2015-08-23 17:42:27 +03:00
|
|
|
if (mmap_offset)
|
|
|
|
|
*mmap_offset = args.mmap_offset;
|
|
|
|
|
|
2016-09-01 23:25:42 -04:00
|
|
|
return vm_obj;
|
2015-02-23 15:54:01 +02:00
|
|
|
|
|
|
|
|
err_object_allocation_failed:
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
free_args.handle = args.handle;
|
|
|
|
|
kmtIoctl(kfd_fd, AMDKFD_IOC_FREE_MEMORY_OF_GPU, &free_args);
|
|
|
|
|
|
2016-09-01 23:25:42 -04:00
|
|
|
return NULL;
|
2015-02-23 15:54:01 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-29 11:21:10 +03:00
|
|
|
#ifdef DEBUG_PRINT_APERTURE
|
2015-02-22 13:06:50 +02:00
|
|
|
static void aperture_print(aperture_t *app)
|
|
|
|
|
{
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("\t Base: %p\n", app->base);
|
|
|
|
|
pr_info("\t Limit: %p\n", app->limit);
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static void manageable_aperture_print(manageable_aperture_t *app)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
|
|
|
|
vm_area_t *cur = app->vm_ranges;
|
2018-06-28 18:24:54 +08:00
|
|
|
rbtree_node_t *n = rbtree_node_any(&app->tree, LEFT);
|
|
|
|
|
vm_object_t *object;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("\t Base: %p\n", app->base);
|
|
|
|
|
pr_info("\t Limit: %p\n", app->limit);
|
|
|
|
|
pr_info("\t Ranges:\n");
|
2015-02-22 13:06:50 +02:00
|
|
|
while (cur) {
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("\t\t Range [%p - %p]\n", cur->start, cur->end);
|
2014-07-29 11:21:10 +03:00
|
|
|
cur = cur->next;
|
|
|
|
|
};
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("\t Objects:\n");
|
2018-06-28 18:24:54 +08:00
|
|
|
while (n) {
|
|
|
|
|
object = vm_object_entry(n, 0);
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("\t\t Object [%p - %" PRIu64 "]\n",
|
2015-02-22 13:06:50 +02:00
|
|
|
object->start, object->size);
|
2018-06-28 18:24:54 +08:00
|
|
|
n = rbtree_next(&app->tree, n);
|
|
|
|
|
}
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
void fmm_print(uint32_t gpu_id)
|
|
|
|
|
{
|
2015-11-25 18:00:42 -05:00
|
|
|
int32_t gpu_mem_id = gpu_mem_find_by_gpu_id(gpu_id);
|
2015-02-22 13:06:50 +02:00
|
|
|
|
2015-11-25 18:00:42 -05:00
|
|
|
if (gpu_mem_id >= 0) { /* Found */
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("LDS aperture:\n");
|
2015-11-25 18:00:42 -05:00
|
|
|
aperture_print(&gpu_mem[gpu_mem_id].lds_aperture);
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("GPUVM aperture:\n");
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_print(&gpu_mem[gpu_mem_id].gpuvm_aperture);
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("Scratch aperture:\n");
|
2018-08-04 16:56:15 -04:00
|
|
|
aperture_print(&gpu_mem[gpu_mem_id].scratch_aperture);
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("Scratch backing memory:\n");
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_print(&gpu_mem[gpu_mem_id].scratch_physical);
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
2015-11-25 18:00:42 -05:00
|
|
|
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("dGPU aperture:\n");
|
2018-08-10 17:05:42 -04:00
|
|
|
manageable_aperture_print(svm.dgpu_aperture);
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("dGPU alt aperture:\n");
|
2018-08-10 17:05:42 -04:00
|
|
|
if (svm.dgpu_aperture == svm.dgpu_alt_aperture)
|
|
|
|
|
pr_info("\t Alias of dGPU aperture\n");
|
|
|
|
|
else
|
|
|
|
|
manageable_aperture_print(svm.dgpu_alt_aperture);
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
#else
|
2015-02-22 13:06:50 +02:00
|
|
|
void fmm_print(uint32_t gpu_id)
|
|
|
|
|
{
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
static void fmm_release_scratch(uint32_t gpu_id)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
2015-10-17 02:50:50 -04:00
|
|
|
int32_t gpu_mem_id;
|
|
|
|
|
uint64_t size;
|
|
|
|
|
vm_object_t *obj;
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2018-06-28 18:24:54 +08:00
|
|
|
rbtree_node_t *n;
|
2015-10-17 02:50:50 -04:00
|
|
|
|
|
|
|
|
gpu_mem_id = gpu_mem_find_by_gpu_id(gpu_id);
|
|
|
|
|
if (gpu_mem_id < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
aperture = &gpu_mem[gpu_mem_id].scratch_physical;
|
|
|
|
|
|
|
|
|
|
size = VOID_PTRS_SUB(aperture->limit, aperture->base) + 1;
|
|
|
|
|
|
|
|
|
|
if (topology_is_dgpu(gpu_mem[gpu_mem_id].device_id)) {
|
|
|
|
|
/* unmap and remove all remaining objects */
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2018-06-28 18:24:54 +08:00
|
|
|
while ((n = rbtree_node_any(&aperture->tree, MID))) {
|
|
|
|
|
obj = vm_object_entry(n, 0);
|
|
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
void *obj_addr = obj->start;
|
2017-04-20 08:25:00 -04:00
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
_fmm_unmap_from_gpu_scratch(gpu_id, aperture, obj_addr);
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
}
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
/* release address space */
|
2018-08-10 17:05:42 -04:00
|
|
|
pthread_mutex_lock(&svm.dgpu_aperture->fmm_mutex);
|
|
|
|
|
aperture_release_area(svm.dgpu_aperture,
|
2015-10-17 02:50:50 -04:00
|
|
|
gpu_mem[gpu_mem_id].scratch_physical.base,
|
|
|
|
|
size);
|
2018-08-10 17:05:42 -04:00
|
|
|
pthread_mutex_unlock(&svm.dgpu_aperture->fmm_mutex);
|
2015-10-17 02:50:50 -04:00
|
|
|
} else
|
|
|
|
|
/* release address space */
|
|
|
|
|
munmap(gpu_mem[gpu_mem_id].scratch_physical.base, size);
|
|
|
|
|
|
|
|
|
|
/* invalidate scratch backing aperture */
|
|
|
|
|
gpu_mem[gpu_mem_id].scratch_physical.base = NULL;
|
|
|
|
|
gpu_mem[gpu_mem_id].scratch_physical.limit = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-26 16:12:09 -04:00
|
|
|
static uint32_t fmm_translate_hsa_to_ioc_flags(HsaMemFlags flags)
|
|
|
|
|
{
|
|
|
|
|
uint32_t ioc_flags = 0;
|
|
|
|
|
|
|
|
|
|
if (flags.ui32.AQLQueueMemory)
|
|
|
|
|
ioc_flags |= KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM;
|
2017-08-15 19:18:03 -04:00
|
|
|
if (!flags.ui32.ReadOnly)
|
|
|
|
|
ioc_flags |= KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE;
|
2017-05-26 16:12:09 -04:00
|
|
|
/* TODO: Since, ROCr interfaces doesn't allow caller to set page
|
|
|
|
|
* permissions, mark all user allocations with exec permission.
|
|
|
|
|
* Check for flags.ui32.ExecuteAccess once ROCr is ready.
|
|
|
|
|
*/
|
2017-08-15 19:18:03 -04:00
|
|
|
ioc_flags |= KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE;
|
2017-05-26 16:12:09 -04:00
|
|
|
return ioc_flags;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
#define SCRATCH_ALIGN 0x10000
|
|
|
|
|
void *fmm_allocate_scratch(uint32_t gpu_id, uint64_t MemorySizeInBytes)
|
|
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture_phy;
|
2017-08-15 19:18:03 -04:00
|
|
|
struct kfd_ioctl_set_scratch_backing_va_args args = {0};
|
2015-06-09 05:37:05 +03:00
|
|
|
int32_t gpu_mem_id;
|
|
|
|
|
void *mem = NULL;
|
2015-10-17 02:50:50 -04:00
|
|
|
uint64_t aligned_size = ALIGN_UP(MemorySizeInBytes, SCRATCH_ALIGN);
|
2015-06-09 05:37:05 +03:00
|
|
|
|
|
|
|
|
/* Retrieve gpu_mem id according to gpu_id */
|
|
|
|
|
gpu_mem_id = gpu_mem_find_by_gpu_id(gpu_id);
|
|
|
|
|
if (gpu_mem_id < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
aperture_phy = &gpu_mem[gpu_mem_id].scratch_physical;
|
2017-04-20 08:25:00 -04:00
|
|
|
if (aperture_phy->base || aperture_phy->limit)
|
2015-10-17 02:50:50 -04:00
|
|
|
/* Scratch was already allocated for this GPU */
|
2015-06-09 05:37:05 +03:00
|
|
|
return NULL;
|
|
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
/* Allocate address space for scratch backing, 64KB aligned */
|
|
|
|
|
if (topology_is_dgpu(gpu_mem[gpu_mem_id].device_id)) {
|
2018-08-10 17:05:42 -04:00
|
|
|
pthread_mutex_lock(&svm.dgpu_aperture->fmm_mutex);
|
2015-10-17 02:50:50 -04:00
|
|
|
mem = aperture_allocate_area_aligned(
|
2018-08-10 17:05:42 -04:00
|
|
|
svm.dgpu_aperture,
|
2018-08-04 15:58:23 -04:00
|
|
|
aligned_size, SCRATCH_ALIGN);
|
2018-08-10 17:05:42 -04:00
|
|
|
pthread_mutex_unlock(&svm.dgpu_aperture->fmm_mutex);
|
2015-10-17 02:50:50 -04:00
|
|
|
} else {
|
|
|
|
|
uint64_t aligned_padded_size = aligned_size +
|
|
|
|
|
SCRATCH_ALIGN - PAGE_SIZE;
|
|
|
|
|
void *padded_end, *aligned_start, *aligned_end;
|
2017-04-20 08:25:00 -04:00
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
mem = mmap(0, aligned_padded_size,
|
|
|
|
|
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
|
|
|
|
|
-1, 0);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!mem)
|
2015-10-17 02:50:50 -04:00
|
|
|
return NULL;
|
|
|
|
|
/* align start and unmap padding */
|
|
|
|
|
padded_end = VOID_PTR_ADD(mem, aligned_padded_size);
|
|
|
|
|
aligned_start = (void *)ALIGN_UP((uint64_t)mem, SCRATCH_ALIGN);
|
|
|
|
|
aligned_end = VOID_PTR_ADD(aligned_start, aligned_size);
|
|
|
|
|
if (aligned_start > mem)
|
|
|
|
|
munmap(mem, VOID_PTRS_SUB(aligned_start, mem));
|
|
|
|
|
if (aligned_end < padded_end)
|
|
|
|
|
munmap(aligned_end,
|
|
|
|
|
VOID_PTRS_SUB(padded_end, aligned_end));
|
|
|
|
|
mem = aligned_start;
|
|
|
|
|
}
|
2015-06-09 05:37:05 +03:00
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
/* Remember scratch backing aperture for later */
|
|
|
|
|
aperture_phy->base = mem;
|
|
|
|
|
aperture_phy->limit = VOID_PTR_ADD(mem, aligned_size-1);
|
2018-08-04 19:45:54 -04:00
|
|
|
aperture_phy->is_cpu_accessible = true;
|
2015-10-17 02:50:50 -04:00
|
|
|
|
2017-08-15 19:18:03 -04:00
|
|
|
/* Program SH_HIDDEN_PRIVATE_BASE */
|
2015-06-09 05:37:05 +03:00
|
|
|
args.gpu_id = gpu_id;
|
2015-10-17 02:50:50 -04:00
|
|
|
args.va_addr = ((uint64_t)mem) >> 16;
|
2015-06-09 05:37:05 +03:00
|
|
|
|
2017-08-15 19:18:03 -04:00
|
|
|
if (kmtIoctl(kfd_fd, AMDKFD_IOC_SET_SCRATCH_BACKING_VA, &args)) {
|
2015-10-17 02:50:50 -04:00
|
|
|
fmm_release_scratch(gpu_id);
|
2015-06-09 05:37:05 +03:00
|
|
|
return NULL;
|
2015-10-17 02:50:50 -04:00
|
|
|
}
|
2015-06-09 05:37:05 +03:00
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
return mem;
|
2014-10-13 11:29:39 +03:00
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static void *__fmm_allocate_device(uint32_t gpu_id, uint64_t MemorySizeInBytes,
|
2018-08-04 15:58:23 -04:00
|
|
|
manageable_aperture_t *aperture, uint64_t *mmap_offset,
|
2016-09-01 23:25:42 -04:00
|
|
|
uint32_t flags, vm_object_t **vm_obj)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
|
|
|
|
void *mem = NULL;
|
2016-09-01 23:25:42 -04:00
|
|
|
vm_object_t *obj;
|
|
|
|
|
|
2015-02-23 15:54:01 +02:00
|
|
|
/* Check that aperture is properly initialized/supported */
|
|
|
|
|
if (!aperture_is_valid(aperture->base, aperture->limit))
|
2015-02-22 13:06:50 +02:00
|
|
|
return NULL;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/* Allocate address space */
|
2015-02-23 15:54:01 +02:00
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2018-08-04 15:58:23 -04:00
|
|
|
mem = aperture_allocate_area(aperture, MemorySizeInBytes);
|
2015-02-23 15:54:01 +02:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now that we have the area reserved, allocate memory in the device
|
|
|
|
|
* itself
|
|
|
|
|
*/
|
2017-12-04 10:23:55 -05:00
|
|
|
obj = fmm_allocate_memory_object(gpu_id, mem,
|
2016-09-01 23:25:42 -04:00
|
|
|
MemorySizeInBytes, aperture, mmap_offset, flags);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!obj) {
|
2015-02-23 15:54:01 +02:00
|
|
|
/*
|
|
|
|
|
* allocation of memory in device failed.
|
|
|
|
|
* Release region in aperture
|
|
|
|
|
*/
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
aperture_release_area(aperture, mem, MemorySizeInBytes);
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2015-03-19 10:09:37 +02:00
|
|
|
|
|
|
|
|
/* Assign NULL to mem to indicate failure to calling function */
|
|
|
|
|
mem = NULL;
|
2015-02-23 15:54:01 +02:00
|
|
|
}
|
2016-09-01 23:25:42 -04:00
|
|
|
if (vm_obj)
|
|
|
|
|
*vm_obj = obj;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 17:52:25 +02:00
|
|
|
void *fmm_allocate_device(uint32_t gpu_id, uint64_t MemorySizeInBytes, HsaMemFlags flags)
|
2015-08-23 17:42:27 +03:00
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2015-08-23 17:42:27 +03:00
|
|
|
int32_t gpu_mem_id;
|
2018-08-04 15:58:23 -04:00
|
|
|
uint32_t ioc_flags = KFD_IOC_ALLOC_MEM_FLAGS_VRAM;
|
2016-02-17 17:52:25 +02:00
|
|
|
uint64_t size, mmap_offset;
|
|
|
|
|
void *mem;
|
2016-09-01 23:25:42 -04:00
|
|
|
vm_object_t *vm_obj = NULL;
|
2015-08-23 17:42:27 +03:00
|
|
|
|
|
|
|
|
/* Retrieve gpu_mem id according to gpu_id */
|
|
|
|
|
gpu_mem_id = gpu_mem_find_by_gpu_id(gpu_id);
|
|
|
|
|
if (gpu_mem_id < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2016-02-17 17:52:25 +02:00
|
|
|
size = MemorySizeInBytes;
|
|
|
|
|
|
2017-05-01 19:19:38 -04:00
|
|
|
if (flags.ui32.HostAccess)
|
|
|
|
|
ioc_flags |= KFD_IOC_ALLOC_MEM_FLAGS_PUBLIC;
|
|
|
|
|
|
2017-05-26 16:12:09 -04:00
|
|
|
ioc_flags |= fmm_translate_hsa_to_ioc_flags(flags);
|
|
|
|
|
|
2018-05-03 12:03:22 -04:00
|
|
|
if (topology_is_svm_needed(get_device_id_by_gpu_id(gpu_id))) {
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2017-05-26 16:12:09 -04:00
|
|
|
if (flags.ui32.AQLQueueMemory)
|
2016-02-17 17:52:25 +02:00
|
|
|
size = MemorySizeInBytes * 2;
|
2015-09-23 15:08:33 -04:00
|
|
|
} else {
|
|
|
|
|
aperture = &gpu_mem[gpu_mem_id].gpuvm_aperture;
|
2015-09-09 14:41:49 +03:00
|
|
|
}
|
|
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
if (!flags.ui32.CoarseGrain || svm.disable_cache)
|
2017-06-29 12:43:14 -04:00
|
|
|
ioc_flags |= KFD_IOC_ALLOC_MEM_FLAGS_COHERENT;
|
|
|
|
|
|
2018-08-04 15:58:23 -04:00
|
|
|
mem = __fmm_allocate_device(gpu_id, size, aperture, &mmap_offset,
|
|
|
|
|
ioc_flags, &vm_obj);
|
2016-09-01 23:25:42 -04:00
|
|
|
|
|
|
|
|
if (mem && vm_obj) {
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
/* Store memory allocation flags, not ioc flags */
|
|
|
|
|
vm_obj->flags = flags.Value;
|
|
|
|
|
gpuid_to_nodeid(gpu_id, &vm_obj->node_id);
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
}
|
2016-02-17 17:52:25 +02:00
|
|
|
|
2017-12-08 15:59:01 -05:00
|
|
|
if (mem && (flags.ui32.HostAccess || hsa_debug)) {
|
2017-10-27 16:17:51 -04:00
|
|
|
int map_fd = mmap_offset >= (1ULL<<40) ? kfd_fd :
|
2018-03-01 17:31:38 -05:00
|
|
|
gpu_mem[gpu_mem_id].drm_render_fd;
|
2017-12-08 15:59:01 -05:00
|
|
|
int prot = flags.ui32.HostAccess ? PROT_READ | PROT_WRITE :
|
|
|
|
|
PROT_NONE;
|
|
|
|
|
int flag = flags.ui32.HostAccess ? MAP_SHARED | MAP_FIXED :
|
|
|
|
|
MAP_PRIVATE|MAP_FIXED;
|
|
|
|
|
void *ret = mmap(mem, MemorySizeInBytes, prot, flag,
|
|
|
|
|
map_fd, mmap_offset);
|
|
|
|
|
|
2016-02-17 17:52:25 +02:00
|
|
|
if (ret == MAP_FAILED) {
|
2018-06-20 13:30:06 +08:00
|
|
|
__fmm_release(vm_obj, aperture);
|
2016-02-17 17:52:25 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mem;
|
2015-08-23 17:42:27 +03:00
|
|
|
}
|
|
|
|
|
|
2016-09-16 15:56:57 -04:00
|
|
|
void *fmm_allocate_doorbell(uint32_t gpu_id, uint64_t MemorySizeInBytes,
|
|
|
|
|
uint64_t doorbell_offset)
|
|
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2016-09-16 15:56:57 -04:00
|
|
|
int32_t gpu_mem_id;
|
|
|
|
|
uint32_t ioc_flags;
|
|
|
|
|
void *mem;
|
|
|
|
|
vm_object_t *vm_obj = NULL;
|
|
|
|
|
|
|
|
|
|
/* Retrieve gpu_mem id according to gpu_id */
|
|
|
|
|
gpu_mem_id = gpu_mem_find_by_gpu_id(gpu_id);
|
|
|
|
|
if (gpu_mem_id < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Use fine-grained aperture */
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_alt_aperture;
|
2016-11-15 14:37:31 -05:00
|
|
|
ioc_flags = KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL |
|
2017-08-15 19:18:03 -04:00
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE |
|
2016-11-15 14:37:31 -05:00
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_COHERENT;
|
2016-09-16 15:56:57 -04:00
|
|
|
|
2018-08-04 15:58:23 -04:00
|
|
|
mem = __fmm_allocate_device(gpu_id, MemorySizeInBytes, aperture, NULL,
|
|
|
|
|
ioc_flags, &vm_obj);
|
2016-09-16 15:56:57 -04:00
|
|
|
|
|
|
|
|
if (mem && vm_obj) {
|
|
|
|
|
HsaMemFlags flags;
|
|
|
|
|
|
|
|
|
|
/* Cook up some flags for storing in the VM object */
|
|
|
|
|
flags.Value = 0;
|
|
|
|
|
flags.ui32.NonPaged = 1;
|
|
|
|
|
flags.ui32.HostAccess = 1;
|
|
|
|
|
flags.ui32.Reserved = 0xBe11;
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
vm_obj->flags = flags.Value;
|
|
|
|
|
gpuid_to_nodeid(gpu_id, &vm_obj->node_id);
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mem) {
|
|
|
|
|
void *ret = mmap(mem, MemorySizeInBytes,
|
|
|
|
|
PROT_READ | PROT_WRITE,
|
|
|
|
|
MAP_SHARED | MAP_FIXED, kfd_fd,
|
|
|
|
|
doorbell_offset);
|
|
|
|
|
if (ret == MAP_FAILED) {
|
2018-06-20 13:30:06 +08:00
|
|
|
__fmm_release(vm_obj, aperture);
|
2016-09-16 15:56:57 -04:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static void *fmm_allocate_host_cpu(uint64_t MemorySizeInBytes,
|
2015-11-30 11:43:09 -05:00
|
|
|
HsaMemFlags flags)
|
2015-08-23 17:42:27 +03:00
|
|
|
{
|
|
|
|
|
void *mem = NULL;
|
2016-09-08 15:01:28 -04:00
|
|
|
vm_object_t *vm_obj;
|
2018-07-03 20:36:44 -04:00
|
|
|
int mmap_prot = PROT_READ;
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2017-10-11 16:57:38 -07:00
|
|
|
if (flags.ui32.ExecuteAccess)
|
|
|
|
|
mmap_prot |= PROT_EXEC;
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2018-07-03 20:36:44 -04:00
|
|
|
if (!flags.ui32.ReadOnly)
|
|
|
|
|
mmap_prot |= PROT_WRITE;
|
|
|
|
|
|
2017-10-11 16:57:38 -07:00
|
|
|
/* mmap will return a pointer with alignment equal to
|
|
|
|
|
* sysconf(_SC_PAGESIZE).
|
|
|
|
|
*/
|
|
|
|
|
mem = mmap(NULL, MemorySizeInBytes, mmap_prot,
|
|
|
|
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2017-10-11 16:57:38 -07:00
|
|
|
if (mem == MAP_FAILED)
|
|
|
|
|
return NULL;
|
2016-09-08 15:01:28 -04:00
|
|
|
|
|
|
|
|
pthread_mutex_lock(&cpuvm_aperture.fmm_mutex);
|
|
|
|
|
vm_obj = aperture_allocate_object(&cpuvm_aperture, mem, 0,
|
|
|
|
|
MemorySizeInBytes, flags.Value);
|
|
|
|
|
if (vm_obj)
|
|
|
|
|
vm_obj->node_id = 0; /* APU systems only have one CPU node */
|
|
|
|
|
pthread_mutex_unlock(&cpuvm_aperture.fmm_mutex);
|
|
|
|
|
|
2015-08-23 17:42:27 +03:00
|
|
|
return mem;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static void *fmm_allocate_host_gpu(uint32_t node_id, uint64_t MemorySizeInBytes,
|
2016-02-06 18:47:40 -05:00
|
|
|
HsaMemFlags flags)
|
2015-08-23 17:42:27 +03:00
|
|
|
{
|
|
|
|
|
void *mem;
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2015-08-23 17:42:27 +03:00
|
|
|
uint64_t mmap_offset;
|
2015-10-19 15:27:36 +03:00
|
|
|
uint32_t ioc_flags;
|
2016-04-08 19:58:32 -04:00
|
|
|
uint64_t size;
|
2018-08-03 03:01:22 -04:00
|
|
|
int32_t gpu_drm_fd;
|
2016-02-06 18:47:40 -05:00
|
|
|
uint32_t gpu_id;
|
2016-09-01 23:25:42 -04:00
|
|
|
vm_object_t *vm_obj = NULL;
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2018-08-03 03:01:22 -04:00
|
|
|
if (!g_first_gpu_mem)
|
2015-08-23 17:42:27 +03:00
|
|
|
return NULL;
|
|
|
|
|
|
2018-08-03 03:01:22 -04:00
|
|
|
gpu_id = g_first_gpu_mem->gpu_id;
|
|
|
|
|
gpu_drm_fd = g_first_gpu_mem->drm_render_fd;
|
|
|
|
|
|
2015-10-19 15:27:36 +03:00
|
|
|
size = MemorySizeInBytes;
|
2016-02-03 18:24:38 -05:00
|
|
|
ioc_flags = 0;
|
2017-06-29 12:43:14 -04:00
|
|
|
if (flags.ui32.CoarseGrain)
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2017-06-29 12:43:14 -04:00
|
|
|
else
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_alt_aperture; /* always coherent */
|
2017-06-29 12:43:14 -04:00
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
if (!flags.ui32.CoarseGrain || svm.disable_cache)
|
2016-11-15 14:37:31 -05:00
|
|
|
ioc_flags |= KFD_IOC_ALLOC_MEM_FLAGS_COHERENT;
|
2017-05-26 16:12:09 -04:00
|
|
|
ioc_flags |= fmm_translate_hsa_to_ioc_flags(flags);
|
2017-06-29 12:43:14 -04:00
|
|
|
|
2017-05-26 16:12:09 -04:00
|
|
|
if (flags.ui32.AQLQueueMemory)
|
2015-10-19 15:27:36 +03:00
|
|
|
size = MemorySizeInBytes * 2;
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2016-02-03 18:24:38 -05:00
|
|
|
/* Paged memory is allocated as a userptr mapping, non-paged
|
2017-04-20 08:25:00 -04:00
|
|
|
* memory is allocated from KFD
|
|
|
|
|
*/
|
2016-02-03 18:24:38 -05:00
|
|
|
if (!flags.ui32.NonPaged && svm.userptr_for_paged_mem) {
|
2017-10-06 19:31:24 -04:00
|
|
|
const unsigned int bits_per_long = sizeof(unsigned long) * 8;
|
|
|
|
|
unsigned long node_mask[node_id / bits_per_long + 1];
|
|
|
|
|
int mode = MPOL_F_STATIC_NODES;
|
|
|
|
|
|
2016-02-03 18:24:38 -05:00
|
|
|
/* Allocate address space */
|
2016-09-01 23:25:42 -04:00
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2018-08-04 15:58:23 -04:00
|
|
|
mem = aperture_allocate_area(aperture, size);
|
2016-09-01 23:25:42 -04:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!mem)
|
2016-02-03 18:24:38 -05:00
|
|
|
return NULL;
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2017-10-06 19:31:24 -04:00
|
|
|
/* Bind to NUMA node */
|
|
|
|
|
memset(node_mask, 0, sizeof(node_mask));
|
|
|
|
|
node_mask[node_id / bits_per_long] = 1UL << (node_id % bits_per_long);
|
|
|
|
|
mode |= flags.ui32.NoSubstitute ? MPOL_BIND : MPOL_PREFERRED;
|
|
|
|
|
if (mbind(mem, MemorySizeInBytes, mode, node_mask, node_id+1, 0))
|
|
|
|
|
pr_warn("Failed to set NUMA policy for %lu pages at %p\n",
|
|
|
|
|
MemorySizeInBytes >> 12, mem);
|
|
|
|
|
|
2016-02-03 18:24:38 -05:00
|
|
|
/* Map anonymous pages */
|
|
|
|
|
if (mmap(mem, MemorySizeInBytes, PROT_READ | PROT_WRITE,
|
|
|
|
|
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)
|
|
|
|
|
== MAP_FAILED) {
|
|
|
|
|
/* Release address space */
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
aperture_release_area(aperture, mem, size);
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2016-02-06 18:47:40 -05:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2016-02-03 18:24:38 -05:00
|
|
|
|
2017-02-21 14:13:05 -05:00
|
|
|
/* Mappings in the DGPU aperture don't need to be copied on
|
|
|
|
|
* fork. This avoids MMU notifiers and evictions due to user
|
2017-04-20 08:25:00 -04:00
|
|
|
* memory mappings on fork.
|
|
|
|
|
*/
|
2017-02-21 14:13:05 -05:00
|
|
|
madvise(mem, MemorySizeInBytes, MADV_DONTFORK);
|
|
|
|
|
|
2016-02-03 18:24:38 -05:00
|
|
|
/* Create userptr BO */
|
|
|
|
|
mmap_offset = (uint64_t)mem;
|
|
|
|
|
ioc_flags |= KFD_IOC_ALLOC_MEM_FLAGS_USERPTR;
|
2017-12-04 10:23:55 -05:00
|
|
|
vm_obj = fmm_allocate_memory_object(gpu_id, mem, size,
|
2016-02-03 18:24:38 -05:00
|
|
|
aperture, &mmap_offset,
|
|
|
|
|
ioc_flags);
|
|
|
|
|
if (!vm_obj) {
|
|
|
|
|
/* Release address space */
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
aperture_release_area(aperture, mem, size);
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2017-05-01 19:19:38 -04:00
|
|
|
ioc_flags |= KFD_IOC_ALLOC_MEM_FLAGS_GTT;
|
2018-08-04 15:58:23 -04:00
|
|
|
mem = __fmm_allocate_device(gpu_id, size, aperture,
|
|
|
|
|
&mmap_offset, ioc_flags, &vm_obj);
|
2016-02-03 18:24:38 -05:00
|
|
|
|
|
|
|
|
if (mem && flags.ui32.HostAccess) {
|
2018-08-03 03:01:22 -04:00
|
|
|
int map_fd = mmap_offset >= (1ULL<<40) ? kfd_fd : gpu_drm_fd;
|
2016-02-03 18:24:38 -05:00
|
|
|
void *ret = mmap(mem, MemorySizeInBytes,
|
|
|
|
|
PROT_READ | PROT_WRITE,
|
2017-10-27 16:17:51 -04:00
|
|
|
MAP_SHARED | MAP_FIXED, map_fd, mmap_offset);
|
2016-02-03 18:24:38 -05:00
|
|
|
if (ret == MAP_FAILED) {
|
2018-06-20 13:30:06 +08:00
|
|
|
__fmm_release(vm_obj, aperture);
|
2016-02-03 18:24:38 -05:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flags.ui32.AQLQueueMemory) {
|
|
|
|
|
uint64_t my_buf_size = ALIGN_UP(size, aperture->align) / 2;
|
2017-04-20 08:25:00 -04:00
|
|
|
|
2016-02-03 18:24:38 -05:00
|
|
|
memset(ret, 0, MemorySizeInBytes);
|
|
|
|
|
mmap(VOID_PTR_ADD(mem, my_buf_size), MemorySizeInBytes,
|
|
|
|
|
PROT_READ | PROT_WRITE,
|
2017-10-27 16:17:51 -04:00
|
|
|
MAP_SHARED | MAP_FIXED, map_fd, mmap_offset);
|
2016-02-03 18:24:38 -05:00
|
|
|
}
|
2016-02-06 18:47:40 -05:00
|
|
|
}
|
2015-08-23 17:42:27 +03:00
|
|
|
}
|
|
|
|
|
|
2016-02-03 18:24:38 -05:00
|
|
|
if (mem && vm_obj) {
|
|
|
|
|
/* Store memory allocation flags, not ioc flags */
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
vm_obj->flags = flags.Value;
|
|
|
|
|
vm_obj->node_id = node_id;
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
}
|
2015-12-30 13:30:23 +02:00
|
|
|
|
2016-02-06 18:47:40 -05:00
|
|
|
return mem;
|
2015-08-23 17:42:27 +03:00
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
void *fmm_allocate_host(uint32_t node_id, uint64_t MemorySizeInBytes,
|
2016-09-01 23:25:42 -04:00
|
|
|
HsaMemFlags flags)
|
2015-08-23 17:42:27 +03:00
|
|
|
{
|
2016-02-06 18:47:40 -05:00
|
|
|
if (is_dgpu)
|
2016-09-01 23:25:42 -04:00
|
|
|
return fmm_allocate_host_gpu(node_id, MemorySizeInBytes, flags);
|
2015-11-30 11:43:09 -05:00
|
|
|
return fmm_allocate_host_cpu(MemorySizeInBytes, flags);
|
2015-08-23 17:42:27 +03:00
|
|
|
}
|
|
|
|
|
|
2018-06-20 13:30:06 +08:00
|
|
|
static void __fmm_release(vm_object_t *object, manageable_aperture_t *aperture)
|
2015-02-23 15:54:01 +02:00
|
|
|
{
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_free_memory_of_gpu_args args = {0};
|
2015-02-23 15:54:01 +02:00
|
|
|
|
2018-06-20 13:30:06 +08:00
|
|
|
if (!object)
|
2015-02-23 15:54:01 +02:00
|
|
|
return;
|
2018-06-25 14:23:16 -04:00
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
|
2017-02-06 15:49:12 -05:00
|
|
|
/* If memory is user memory and it's still GPU mapped, munmap
|
|
|
|
|
* would cause an eviction. If the restore happens quickly
|
|
|
|
|
* enough, restore would also fail with an error message. So
|
2017-04-20 08:25:00 -04:00
|
|
|
* free the BO before unmapping the pages.
|
|
|
|
|
*/
|
2017-02-06 15:49:12 -05:00
|
|
|
args.handle = object->handle;
|
|
|
|
|
kmtIoctl(kfd_fd, AMDKFD_IOC_FREE_MEMORY_OF_GPU, &args);
|
|
|
|
|
|
2018-08-04 19:45:54 -04:00
|
|
|
aperture_release_area(aperture, object->start, object->size);
|
2015-02-23 15:54:01 +02:00
|
|
|
vm_remove_object(aperture, object);
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
}
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2018-06-20 13:30:06 +08:00
|
|
|
HSAKMT_STATUS fmm_release(void *address)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
2014-07-29 11:21:10 +03:00
|
|
|
uint32_t i;
|
2018-06-25 14:23:16 -04:00
|
|
|
vm_object_t *object = NULL;
|
2018-06-20 13:30:06 +08:00
|
|
|
manageable_aperture_t *aperture = NULL;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2018-06-20 13:30:06 +08:00
|
|
|
for (i = 0; i < gpu_mem_count; i++) {
|
2015-02-22 13:06:50 +02:00
|
|
|
if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID)
|
2014-07-29 11:21:10 +03:00
|
|
|
continue;
|
2015-11-25 18:00:42 -05:00
|
|
|
if (address >= gpu_mem[i].scratch_physical.base &&
|
2015-10-17 02:50:50 -04:00
|
|
|
address <= gpu_mem[i].scratch_physical.limit) {
|
|
|
|
|
fmm_release_scratch(gpu_mem[i].gpu_id);
|
2018-06-20 13:30:06 +08:00
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
2015-10-17 02:50:50 -04:00
|
|
|
}
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2015-11-25 18:00:42 -05:00
|
|
|
if (address >= gpu_mem[i].gpuvm_aperture.base &&
|
2015-02-22 13:06:50 +02:00
|
|
|
address <= gpu_mem[i].gpuvm_aperture.limit) {
|
2018-06-20 13:30:06 +08:00
|
|
|
aperture = &gpu_mem[i].gpuvm_aperture;
|
|
|
|
|
break;
|
2015-08-23 17:42:27 +03:00
|
|
|
}
|
2015-11-25 18:00:42 -05:00
|
|
|
}
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2018-06-20 13:30:06 +08:00
|
|
|
if (!aperture) {
|
2018-08-10 17:05:42 -04:00
|
|
|
if (address >= svm.dgpu_aperture->base &&
|
|
|
|
|
address <= svm.dgpu_aperture->limit) {
|
|
|
|
|
aperture = svm.dgpu_aperture;
|
|
|
|
|
} else if (address >= svm.dgpu_alt_aperture->base &&
|
|
|
|
|
address <= svm.dgpu_alt_aperture->limit) {
|
|
|
|
|
aperture = svm.dgpu_alt_aperture;
|
2015-10-02 15:42:02 -04:00
|
|
|
}
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2018-06-20 13:30:06 +08:00
|
|
|
if (aperture) {
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
object = vm_find_object_by_address(aperture, address, 0);
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2018-06-25 14:23:16 -04:00
|
|
|
if (object)
|
|
|
|
|
__fmm_release(object, aperture);
|
2018-06-20 13:30:06 +08:00
|
|
|
if (i < gpu_mem_count)
|
|
|
|
|
fmm_print(gpu_mem[i].gpu_id);
|
|
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* If memory address isn't inside of any defined GPU aperture - it
|
|
|
|
|
* refers to the system memory
|
|
|
|
|
*/
|
2017-10-11 16:57:38 -07:00
|
|
|
uint64_t size = 0;
|
2016-09-08 15:01:28 -04:00
|
|
|
/* Release the vm object in CPUVM */
|
|
|
|
|
pthread_mutex_lock(&cpuvm_aperture.fmm_mutex);
|
2016-09-13 12:44:29 -04:00
|
|
|
object = vm_find_object_by_address(&cpuvm_aperture, address, 0);
|
2017-10-11 16:57:38 -07:00
|
|
|
if (object) {
|
|
|
|
|
size = object->size;
|
2016-09-08 15:01:28 -04:00
|
|
|
vm_remove_object(&cpuvm_aperture, object);
|
2017-10-11 16:57:38 -07:00
|
|
|
}
|
2016-09-08 15:01:28 -04:00
|
|
|
pthread_mutex_unlock(&cpuvm_aperture.fmm_mutex);
|
|
|
|
|
/* Free the memory from the system */
|
2017-10-11 16:57:38 -07:00
|
|
|
if (size)
|
|
|
|
|
munmap(address, size);
|
2015-12-30 13:30:23 +02:00
|
|
|
}
|
2018-06-25 14:23:16 -04:00
|
|
|
|
|
|
|
|
return object ?
|
|
|
|
|
HSAKMT_STATUS_SUCCESS :
|
|
|
|
|
HSAKMT_STATUS_MEMORY_NOT_REGISTERED;
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2015-10-02 15:42:02 -04:00
|
|
|
static int fmm_set_memory_policy(uint32_t gpu_id, int default_policy, int alt_policy,
|
|
|
|
|
uintptr_t alt_base, uint64_t alt_size)
|
|
|
|
|
{
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_set_memory_policy_args args = {0};
|
2015-10-02 15:42:02 -04:00
|
|
|
|
|
|
|
|
args.gpu_id = gpu_id;
|
|
|
|
|
args.default_policy = default_policy;
|
|
|
|
|
args.alternate_policy = alt_policy;
|
|
|
|
|
args.alternate_aperture_base = alt_base;
|
|
|
|
|
args.alternate_aperture_size = alt_size;
|
|
|
|
|
|
|
|
|
|
return kmtIoctl(kfd_fd, AMDKFD_IOC_SET_MEMORY_POLICY, &args);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-01 17:50:46 -05:00
|
|
|
static uint32_t get_vm_alignment(uint32_t device_id)
|
|
|
|
|
{
|
2017-04-28 16:55:52 -04:00
|
|
|
int page_size = 0;
|
|
|
|
|
|
2016-03-01 17:50:46 -05:00
|
|
|
if (device_id >= 0x6920 && device_id <= 0x6939) /* Tonga */
|
2017-04-28 16:55:52 -04:00
|
|
|
page_size = TONGA_PAGE_SIZE;
|
|
|
|
|
else if (device_id >= 0x9870 && device_id <= 0x9877) /* Carrizo */
|
|
|
|
|
page_size = TONGA_PAGE_SIZE;
|
|
|
|
|
|
|
|
|
|
return MAX(PAGE_SIZE, page_size);
|
2016-03-01 17:50:46 -05:00
|
|
|
}
|
|
|
|
|
|
2017-08-05 00:45:50 -04:00
|
|
|
static HSAKMT_STATUS get_process_apertures(
|
|
|
|
|
struct kfd_process_device_apertures *process_apertures,
|
|
|
|
|
uint32_t *num_of_nodes)
|
|
|
|
|
{
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_get_process_apertures_new_args args_new = {0};
|
2017-08-05 00:45:50 -04:00
|
|
|
struct kfd_ioctl_get_process_apertures_args args_old;
|
|
|
|
|
|
2018-01-25 13:47:14 -08:00
|
|
|
args_new.kfd_process_device_apertures_ptr = (uintptr_t)process_apertures;
|
|
|
|
|
args_new.num_of_nodes = *num_of_nodes;
|
2017-08-05 00:45:50 -04:00
|
|
|
if (!kmtIoctl(kfd_fd, AMDKFD_IOC_GET_PROCESS_APERTURES_NEW,
|
|
|
|
|
(void *)&args_new)) {
|
|
|
|
|
*num_of_nodes = args_new.num_of_nodes;
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* New IOCTL failed, try the old one in case we're running on
|
|
|
|
|
* a really old kernel */
|
2018-01-25 13:47:14 -08:00
|
|
|
memset(&args_old, 0, sizeof(args_old));
|
|
|
|
|
|
2017-08-05 00:45:50 -04:00
|
|
|
if (kmtIoctl(kfd_fd, AMDKFD_IOC_GET_PROCESS_APERTURES,
|
|
|
|
|
(void *)&args_old))
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
|
|
|
|
|
if (args_old.num_of_nodes < *num_of_nodes)
|
|
|
|
|
*num_of_nodes = args_old.num_of_nodes;
|
|
|
|
|
|
|
|
|
|
memcpy(process_apertures, args_old.process_apertures,
|
|
|
|
|
sizeof(*process_apertures) * *num_of_nodes);
|
|
|
|
|
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-01 17:31:38 -05:00
|
|
|
/* The VMs from DRM render nodes are used by KFD for the lifetime of
|
|
|
|
|
* the process. Therefore we have to keep using the same FDs for the
|
|
|
|
|
* lifetime of the process, even when we close and reopen KFD. There
|
|
|
|
|
* are up to 128 render nodes that we cache in this array.
|
|
|
|
|
*/
|
|
|
|
|
#define DRM_FIRST_RENDER_NODE 128
|
|
|
|
|
#define DRM_LAST_RENDER_NODE 255
|
|
|
|
|
static int drm_render_fds[DRM_LAST_RENDER_NODE + 1 - DRM_FIRST_RENDER_NODE];
|
|
|
|
|
|
|
|
|
|
static int open_drm_render_device(int minor)
|
|
|
|
|
{
|
|
|
|
|
char path[128];
|
|
|
|
|
int index, fd;
|
|
|
|
|
|
|
|
|
|
if (minor < DRM_FIRST_RENDER_NODE || minor > DRM_LAST_RENDER_NODE) {
|
|
|
|
|
pr_err("DRM render minor %d out of range [%d, %d]\n", minor,
|
|
|
|
|
DRM_FIRST_RENDER_NODE, DRM_LAST_RENDER_NODE);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
index = minor - DRM_FIRST_RENDER_NODE;
|
|
|
|
|
|
|
|
|
|
/* If the render node was already opened, keep using the same FD */
|
|
|
|
|
if (drm_render_fds[index])
|
|
|
|
|
return drm_render_fds[index];
|
|
|
|
|
|
|
|
|
|
sprintf(path, "/dev/dri/renderD%d", minor);
|
|
|
|
|
fd = open(path, O_RDWR | O_CLOEXEC);
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
pr_err("Failed to open %s: %s\n", path, strerror(errno));
|
|
|
|
|
return -errno;
|
|
|
|
|
}
|
|
|
|
|
drm_render_fds[index] = fd;
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HSAKMT_STATUS acquire_vm(uint32_t gpu_id, int fd)
|
|
|
|
|
{
|
|
|
|
|
struct kfd_ioctl_acquire_vm_args args;
|
|
|
|
|
|
|
|
|
|
args.gpu_id = gpu_id;
|
|
|
|
|
args.drm_fd = fd;
|
|
|
|
|
pr_info("acquiring VM for %x using %d\n", gpu_id, fd);
|
|
|
|
|
if (kmtIoctl(kfd_fd, AMDKFD_IOC_ACQUIRE_VM, (void *)&args)) {
|
|
|
|
|
pr_err("AMDKFD_IOC_ACQUIRE_VM failed\n");
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-09 14:28:47 -05:00
|
|
|
static void *reserve_address(void *addr, unsigned long long int len)
|
|
|
|
|
{
|
|
|
|
|
void *ret_addr;
|
|
|
|
|
|
|
|
|
|
if (len <= 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
ret_addr = mmap(addr, len, PROT_NONE,
|
|
|
|
|
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
|
|
|
|
if (ret_addr == MAP_FAILED)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return ret_addr;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
/* Managed SVM aperture limits: only reserve up to 40 bits (1TB, what
|
|
|
|
|
* GFX8 supports). Need to find at least 4GB of usable address space.
|
2018-03-09 14:28:47 -05:00
|
|
|
*/
|
2018-01-24 23:02:48 -05:00
|
|
|
#define SVM_RESERVATION_LIMIT ((1ULL << 40) - 1)
|
|
|
|
|
#define SVM_MIN_VM_SIZE (4ULL << 30)
|
|
|
|
|
#define IS_CANONICAL_ADDR(a) ((a) < (1ULL << 47))
|
2018-03-09 14:28:47 -05:00
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
static HSAKMT_STATUS init_svm_apertures(HSAuint64 base, HSAuint64 limit,
|
2018-08-10 17:05:42 -04:00
|
|
|
HSAuint32 align, HSAuint32 guard_pages)
|
2018-03-09 14:28:47 -05:00
|
|
|
{
|
2018-01-24 23:02:48 -05:00
|
|
|
const HSAuint64 ADDR_INC = GPU_HUGE_PAGE_SIZE;
|
2018-08-03 22:02:25 -04:00
|
|
|
HSAuint64 len, map_size, alt_base, alt_size;
|
2018-01-24 23:02:48 -05:00
|
|
|
bool found = false;
|
2018-03-09 14:28:47 -05:00
|
|
|
void *addr, *ret_addr;
|
2018-01-24 23:02:48 -05:00
|
|
|
|
|
|
|
|
/* If we already have an SVM aperture initialized (from a
|
|
|
|
|
* parent process), keep using it
|
|
|
|
|
*/
|
|
|
|
|
if (dgpu_shared_aperture_limit)
|
2018-03-09 14:28:47 -05:00
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
base = ALIGN_UP(base, GPU_HUGE_PAGE_SIZE);
|
|
|
|
|
limit = ((limit + 1) & ~(HSAuint64)(GPU_HUGE_PAGE_SIZE - 1)) - 1;
|
|
|
|
|
if (limit > SVM_RESERVATION_LIMIT)
|
|
|
|
|
limit = SVM_RESERVATION_LIMIT;
|
|
|
|
|
if (base >= limit) {
|
|
|
|
|
pr_err("No SVM range compatible with all GPU and software constraints\n");
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
2018-03-09 14:28:47 -05:00
|
|
|
}
|
|
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
/* Try to reserve address space for SVM.
|
|
|
|
|
*
|
|
|
|
|
* Inner loop: try start addresses in huge-page increments up
|
|
|
|
|
* to half the VM size we're trying to reserve
|
|
|
|
|
*
|
|
|
|
|
* Outer loop: reduce size of the allocation by factor 2 at a
|
|
|
|
|
* time and print a warning for every reduction
|
|
|
|
|
*/
|
|
|
|
|
for (len = limit - base + 1; !found && len >= SVM_MIN_VM_SIZE;
|
|
|
|
|
len = (len + 1) >> 1) {
|
|
|
|
|
for (addr = (void *)base, ret_addr = NULL;
|
|
|
|
|
(HSAuint64)addr + ((len + 1) >> 1) - 1 <= limit;
|
|
|
|
|
addr = (void *)((HSAuint64)addr + ADDR_INC)) {
|
|
|
|
|
HSAuint64 top = MIN((HSAuint64)addr + len, limit+1);
|
|
|
|
|
|
2018-08-03 22:02:25 -04:00
|
|
|
map_size = (top - (HSAuint64)addr) &
|
|
|
|
|
~(HSAuint64)(PAGE_SIZE - 1);
|
|
|
|
|
if (map_size < SVM_MIN_VM_SIZE)
|
2018-01-24 23:02:48 -05:00
|
|
|
break;
|
2018-08-03 22:02:25 -04:00
|
|
|
|
|
|
|
|
ret_addr = reserve_address(addr, map_size);
|
2018-03-09 14:28:47 -05:00
|
|
|
if (!ret_addr)
|
|
|
|
|
break;
|
2018-01-24 23:02:48 -05:00
|
|
|
if ((HSAuint64)ret_addr + ((len + 1) >> 1) - 1 <= limit)
|
2018-03-09 14:28:47 -05:00
|
|
|
/* At least half the returned address
|
|
|
|
|
* space is GPU addressable, we'll
|
|
|
|
|
* take it
|
|
|
|
|
*/
|
|
|
|
|
break;
|
2018-08-03 22:02:25 -04:00
|
|
|
munmap(ret_addr, map_size);
|
|
|
|
|
ret_addr = NULL;
|
2018-03-09 14:28:47 -05:00
|
|
|
}
|
|
|
|
|
if (!ret_addr) {
|
|
|
|
|
pr_warn("Failed to reserve %uGB for SVM ...\n",
|
|
|
|
|
(unsigned int)(len >> 30));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2018-01-24 23:02:48 -05:00
|
|
|
if ((HSAuint64)ret_addr + SVM_MIN_VM_SIZE - 1 > limit) {
|
2018-03-09 14:28:47 -05:00
|
|
|
/* addressable size is less than the minimum */
|
|
|
|
|
pr_warn("Got %uGB for SVM at %p with only %dGB usable ...\n",
|
2018-08-03 22:02:25 -04:00
|
|
|
(unsigned int)(map_size >> 30), ret_addr,
|
2018-01-24 23:02:48 -05:00
|
|
|
(int)((limit - (HSAint64)ret_addr) >> 30));
|
2018-08-03 22:02:25 -04:00
|
|
|
munmap(ret_addr, map_size);
|
|
|
|
|
ret_addr = NULL;
|
2018-03-09 14:28:47 -05:00
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
pr_err("Failed to reserve SVM address range. Giving up.\n");
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
base = (HSAuint64)ret_addr;
|
2018-08-03 22:02:25 -04:00
|
|
|
if (base + map_size - 1 > limit)
|
2018-03-09 14:28:47 -05:00
|
|
|
/* trim the tail that's not GPU-addressable */
|
2018-08-03 22:02:25 -04:00
|
|
|
munmap((void *)(limit + 1), base + map_size - 1 - limit);
|
2018-01-24 23:02:48 -05:00
|
|
|
else
|
2018-08-03 22:02:25 -04:00
|
|
|
limit = base + map_size - 1;
|
2018-01-24 23:02:48 -05:00
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
/* init two apertures for non-coherent and coherent memory */
|
|
|
|
|
svm.apertures[SVM_DEFAULT].base = dgpu_shared_aperture_base = ret_addr;
|
|
|
|
|
svm.apertures[SVM_DEFAULT].limit = dgpu_shared_aperture_limit = (void *)limit;
|
|
|
|
|
svm.apertures[SVM_DEFAULT].align = align;
|
|
|
|
|
svm.apertures[SVM_DEFAULT].guard_pages = guard_pages;
|
|
|
|
|
svm.apertures[SVM_DEFAULT].is_cpu_accessible = true;
|
2018-01-24 23:02:48 -05:00
|
|
|
|
|
|
|
|
/* Use the first 1/4 of the dGPU aperture as
|
|
|
|
|
* alternate aperture for coherent access.
|
|
|
|
|
* Base and size must be 64KB aligned.
|
|
|
|
|
*/
|
2018-08-10 17:05:42 -04:00
|
|
|
alt_base = (HSAuint64)svm.apertures[SVM_DEFAULT].base;
|
|
|
|
|
alt_size = (VOID_PTRS_SUB(svm.apertures[SVM_DEFAULT].limit,
|
|
|
|
|
svm.apertures[SVM_DEFAULT].base) + 1) >> 2;
|
2018-01-24 23:02:48 -05:00
|
|
|
alt_base = (alt_base + 0xffff) & ~0xffffULL;
|
|
|
|
|
alt_size = (alt_size + 0xffff) & ~0xffffULL;
|
2018-08-10 17:05:42 -04:00
|
|
|
svm.apertures[SVM_COHERENT].base = (void *)alt_base;
|
|
|
|
|
svm.apertures[SVM_COHERENT].limit = (void *)(alt_base + alt_size - 1);
|
|
|
|
|
svm.apertures[SVM_COHERENT].align = align;
|
|
|
|
|
svm.apertures[SVM_COHERENT].guard_pages = guard_pages;
|
|
|
|
|
svm.apertures[SVM_COHERENT].is_cpu_accessible = true;
|
2018-01-24 23:02:48 -05:00
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
svm.apertures[SVM_DEFAULT].base = VOID_PTR_ADD(svm.apertures[SVM_COHERENT].limit, 1);
|
2018-01-24 23:02:48 -05:00
|
|
|
|
|
|
|
|
pr_info("SVM alt (coherent): %12p - %12p\n",
|
2018-08-10 17:05:42 -04:00
|
|
|
svm.apertures[SVM_COHERENT].base, svm.apertures[SVM_COHERENT].limit);
|
2018-01-24 23:02:48 -05:00
|
|
|
pr_info("SVM (non-coherent): %12p - %12p\n",
|
2018-08-10 17:05:42 -04:00
|
|
|
svm.apertures[SVM_DEFAULT].base, svm.apertures[SVM_DEFAULT].limit);
|
|
|
|
|
|
|
|
|
|
svm.dgpu_aperture = &svm.apertures[SVM_DEFAULT];
|
|
|
|
|
svm.dgpu_alt_aperture = &svm.apertures[SVM_COHERENT];
|
2018-03-09 14:28:47 -05:00
|
|
|
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
static void fmm_init_rbtree(void)
|
|
|
|
|
{
|
|
|
|
|
static int once;
|
|
|
|
|
int i = gpu_mem_count;
|
|
|
|
|
|
|
|
|
|
if (once++ == 0) {
|
2018-08-10 17:05:42 -04:00
|
|
|
rbtree_init(&svm.apertures[SVM_DEFAULT].tree);
|
|
|
|
|
rbtree_init(&svm.apertures[SVM_DEFAULT].user_tree);
|
|
|
|
|
rbtree_init(&svm.apertures[SVM_COHERENT].tree);
|
|
|
|
|
rbtree_init(&svm.apertures[SVM_COHERENT].user_tree);
|
2018-06-28 18:24:54 +08:00
|
|
|
rbtree_init(&cpuvm_aperture.tree);
|
|
|
|
|
rbtree_init(&cpuvm_aperture.user_tree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (i--) {
|
|
|
|
|
rbtree_init(&gpu_mem[i].scratch_physical.tree);
|
|
|
|
|
rbtree_init(&gpu_mem[i].scratch_physical.user_tree);
|
|
|
|
|
rbtree_init(&gpu_mem[i].gpuvm_aperture.tree);
|
|
|
|
|
rbtree_init(&gpu_mem[i].gpuvm_aperture.user_tree);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-14 17:07:28 -05:00
|
|
|
HSAKMT_STATUS fmm_init_process_apertures(unsigned int NumNodes)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
2018-08-03 03:01:22 -04:00
|
|
|
uint32_t i;
|
2017-04-20 08:25:00 -04:00
|
|
|
int32_t gpu_mem_id = 0;
|
2015-08-23 17:42:27 +03:00
|
|
|
uint32_t gpu_id;
|
|
|
|
|
HsaNodeProperties props;
|
2017-04-20 08:25:00 -04:00
|
|
|
struct kfd_process_device_apertures *process_apertures;
|
2017-08-05 00:45:50 -04:00
|
|
|
uint32_t num_of_nodes;
|
2015-10-02 15:42:02 -04:00
|
|
|
HSAKMT_STATUS ret = HSAKMT_STATUS_SUCCESS;
|
2017-04-05 20:54:41 -04:00
|
|
|
char *disableCache, *pagedUserptr, *checkUserptr, *guardPagesStr;
|
2017-12-08 15:59:01 -05:00
|
|
|
char *hsaDebug;
|
2017-08-29 15:10:05 -04:00
|
|
|
unsigned int guardPages = 1;
|
2016-08-19 11:42:05 -04:00
|
|
|
struct pci_access *pacc;
|
2018-01-24 23:02:48 -05:00
|
|
|
uint64_t svm_base = 0, svm_limit = 0;
|
|
|
|
|
uint32_t svm_alignment = 0;
|
2016-03-17 18:45:40 -04:00
|
|
|
|
2017-12-08 15:59:01 -05:00
|
|
|
hsaDebug = getenv("HSA_DEBUG");
|
|
|
|
|
hsa_debug = hsaDebug && strcmp(hsaDebug, "0");
|
|
|
|
|
|
2016-03-17 18:45:40 -04:00
|
|
|
/* If HSA_DISABLE_CACHE is set to a non-0 value, disable caching */
|
|
|
|
|
disableCache = getenv("HSA_DISABLE_CACHE");
|
2018-08-10 17:05:42 -04:00
|
|
|
svm.disable_cache = (disableCache && strcmp(disableCache, "0"));
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2017-02-28 12:36:30 -05:00
|
|
|
/* If HSA_USERPTR_FOR_PAGED_MEM is set to a non-0 value,
|
2017-04-20 08:25:00 -04:00
|
|
|
* enable userptr for all paged memory allocations
|
|
|
|
|
*/
|
2016-02-03 18:24:38 -05:00
|
|
|
pagedUserptr = getenv("HSA_USERPTR_FOR_PAGED_MEM");
|
2017-02-28 12:36:30 -05:00
|
|
|
svm.userptr_for_paged_mem = (pagedUserptr && strcmp(pagedUserptr, "0"));
|
2016-02-03 18:24:38 -05:00
|
|
|
|
2017-04-05 17:22:36 -04:00
|
|
|
/* If HSA_CHECK_USERPTR is set to a non-0 value, check all userptrs
|
|
|
|
|
* when they are registered
|
|
|
|
|
*/
|
|
|
|
|
checkUserptr = getenv("HSA_CHECK_USERPTR");
|
|
|
|
|
svm.check_userptr = (checkUserptr && strcmp(checkUserptr, "0"));
|
|
|
|
|
|
2017-08-29 15:10:05 -04:00
|
|
|
/* Specify number of guard pages for SVM apertures, default is 1 */
|
2017-04-05 20:54:41 -04:00
|
|
|
guardPagesStr = getenv("HSA_SVM_GUARD_PAGES");
|
|
|
|
|
if (!guardPagesStr || sscanf(guardPagesStr, "%u", &guardPages) != 1)
|
2017-08-29 15:10:05 -04:00
|
|
|
guardPages = 1;
|
2017-04-05 20:54:41 -04:00
|
|
|
|
2018-08-03 03:01:22 -04:00
|
|
|
gpu_mem_count = 0;
|
|
|
|
|
g_first_gpu_mem = NULL;
|
|
|
|
|
|
2016-01-14 17:07:28 -05:00
|
|
|
/* Trade off - NumNodes includes GPU nodes + CPU Node. So in
|
2017-04-20 08:25:00 -04:00
|
|
|
* systems with CPU node, slightly more memory is allocated than
|
|
|
|
|
* necessary
|
|
|
|
|
*/
|
2016-01-14 17:07:28 -05:00
|
|
|
gpu_mem = (gpu_mem_t *)calloc(NumNodes, sizeof(gpu_mem_t));
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!gpu_mem)
|
2016-01-13 17:27:31 -05:00
|
|
|
return HSAKMT_STATUS_NO_MEMORY;
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
/* Initialize gpu_mem[] from sysfs topology. Rest of the members are
|
|
|
|
|
* set to 0 by calloc. This is necessary because this function
|
|
|
|
|
* gets called before hsaKmtAcquireSystemProperties() is called.
|
|
|
|
|
*/
|
2018-08-03 03:01:22 -04:00
|
|
|
|
2016-08-19 11:42:05 -04:00
|
|
|
pacc = pci_alloc();
|
|
|
|
|
pci_init(pacc);
|
2018-08-03 03:01:22 -04:00
|
|
|
for (i = 0; i < NumNodes; i++) {
|
2016-09-02 12:28:17 -04:00
|
|
|
memset(&props, 0, sizeof(props));
|
2016-08-19 11:42:05 -04:00
|
|
|
ret = topology_sysfs_get_node_props(i, &props, &gpu_id, pacc);
|
2015-10-15 12:03:31 -04:00
|
|
|
if (ret != HSAKMT_STATUS_SUCCESS)
|
2016-01-13 17:27:31 -05:00
|
|
|
goto sysfs_parse_failed;
|
2015-10-15 12:03:31 -04:00
|
|
|
|
2015-12-14 16:25:18 -05:00
|
|
|
/* Skip non-GPU nodes */
|
|
|
|
|
if (gpu_id != 0) {
|
2018-06-27 18:51:33 -04:00
|
|
|
int fd = open_drm_render_device(props.DrmRenderMinor);
|
|
|
|
|
if (fd <= 0) {
|
|
|
|
|
ret = HSAKMT_STATUS_ERROR;
|
2018-03-01 17:31:38 -05:00
|
|
|
goto sysfs_parse_failed;
|
2018-06-27 18:51:33 -04:00
|
|
|
}
|
2018-03-01 17:31:38 -05:00
|
|
|
|
2018-06-27 18:51:33 -04:00
|
|
|
gpu_mem[gpu_mem_count].drm_render_fd = fd;
|
2016-01-13 17:27:31 -05:00
|
|
|
gpu_mem[gpu_mem_count].gpu_id = gpu_id;
|
|
|
|
|
gpu_mem[gpu_mem_count].local_mem_size = props.LocalMemSize;
|
|
|
|
|
gpu_mem[gpu_mem_count].device_id = props.DeviceId;
|
|
|
|
|
gpu_mem[gpu_mem_count].node_id = i;
|
|
|
|
|
gpu_mem[gpu_mem_count].scratch_physical.align = PAGE_SIZE;
|
|
|
|
|
pthread_mutex_init(&gpu_mem[gpu_mem_count].scratch_physical.fmm_mutex, NULL);
|
2016-03-01 17:50:46 -05:00
|
|
|
gpu_mem[gpu_mem_count].gpuvm_aperture.align =
|
|
|
|
|
get_vm_alignment(props.DeviceId);
|
2017-04-05 20:54:41 -04:00
|
|
|
gpu_mem[gpu_mem_count].gpuvm_aperture.guard_pages = guardPages;
|
2016-01-13 17:27:31 -05:00
|
|
|
pthread_mutex_init(&gpu_mem[gpu_mem_count].gpuvm_aperture.fmm_mutex, NULL);
|
2018-08-03 03:01:22 -04:00
|
|
|
|
|
|
|
|
if (!g_first_gpu_mem)
|
|
|
|
|
g_first_gpu_mem = &gpu_mem[gpu_mem_count];
|
|
|
|
|
|
2016-01-13 17:27:31 -05:00
|
|
|
gpu_mem_count++;
|
2015-12-14 16:25:18 -05:00
|
|
|
}
|
2015-10-15 12:03:31 -04:00
|
|
|
}
|
2016-08-19 11:42:05 -04:00
|
|
|
pci_cleanup(pacc);
|
2015-10-15 12:03:31 -04:00
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
/* The ioctl will also return Number of Nodes if
|
|
|
|
|
* args.kfd_process_device_apertures_ptr is set to NULL. This is not
|
|
|
|
|
* required since Number of nodes is already known. Kernel will fill in
|
|
|
|
|
* the apertures in kfd_process_device_apertures_ptr
|
|
|
|
|
*/
|
2017-08-05 00:45:50 -04:00
|
|
|
num_of_nodes = gpu_mem_count;
|
2018-01-25 13:47:14 -08:00
|
|
|
process_apertures = calloc(num_of_nodes, sizeof(struct kfd_process_device_apertures));
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!process_apertures) {
|
2016-01-13 17:27:31 -05:00
|
|
|
ret = HSAKMT_STATUS_NO_MEMORY;
|
|
|
|
|
goto sysfs_parse_failed;
|
|
|
|
|
}
|
2015-12-21 15:42:52 -05:00
|
|
|
|
2017-08-05 00:45:50 -04:00
|
|
|
ret = get_process_apertures(process_apertures, &num_of_nodes);
|
|
|
|
|
if (ret != HSAKMT_STATUS_SUCCESS)
|
2015-12-21 15:42:52 -05:00
|
|
|
goto get_aperture_ioctl_failed;
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2016-01-07 16:28:20 -05:00
|
|
|
all_gpu_id_array_size = 0;
|
2015-12-21 15:42:52 -05:00
|
|
|
all_gpu_id_array = NULL;
|
2017-08-05 00:45:50 -04:00
|
|
|
if (num_of_nodes > 0) {
|
|
|
|
|
all_gpu_id_array = malloc(sizeof(uint32_t) * num_of_nodes);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!all_gpu_id_array) {
|
2015-12-21 15:42:52 -05:00
|
|
|
ret = HSAKMT_STATUS_NO_MEMORY;
|
|
|
|
|
goto get_aperture_ioctl_failed;
|
|
|
|
|
}
|
2016-01-07 16:28:20 -05:00
|
|
|
}
|
|
|
|
|
|
2017-08-05 00:45:50 -04:00
|
|
|
for (i = 0 ; i < num_of_nodes ; i++) {
|
2017-04-20 08:25:00 -04:00
|
|
|
/* Map Kernel process device data node i <--> gpu_mem_id which
|
|
|
|
|
* indexes into gpu_mem[] based on gpu_id
|
|
|
|
|
*/
|
2015-12-21 15:42:52 -05:00
|
|
|
gpu_mem_id = gpu_mem_find_by_gpu_id(process_apertures[i].gpu_id);
|
|
|
|
|
if (gpu_mem_id < 0) {
|
|
|
|
|
ret = HSAKMT_STATUS_ERROR;
|
|
|
|
|
goto invalid_gpu_id;
|
|
|
|
|
}
|
2015-10-15 12:03:31 -04:00
|
|
|
|
2015-12-21 15:42:52 -05:00
|
|
|
all_gpu_id_array[i] = process_apertures[i].gpu_id;
|
2016-01-07 16:28:20 -05:00
|
|
|
all_gpu_id_array_size += sizeof(uint32_t);
|
|
|
|
|
|
2015-10-15 12:03:31 -04:00
|
|
|
gpu_mem[gpu_mem_id].lds_aperture.base =
|
2015-12-21 15:42:52 -05:00
|
|
|
PORT_UINT64_TO_VPTR(process_apertures[i].lds_base);
|
2015-10-15 12:03:31 -04:00
|
|
|
gpu_mem[gpu_mem_id].lds_aperture.limit =
|
2015-12-21 15:42:52 -05:00
|
|
|
PORT_UINT64_TO_VPTR(process_apertures[i].lds_limit);
|
2015-10-15 12:03:31 -04:00
|
|
|
|
|
|
|
|
gpu_mem[gpu_mem_id].scratch_aperture.base =
|
2015-12-21 15:42:52 -05:00
|
|
|
PORT_UINT64_TO_VPTR(process_apertures[i].scratch_base);
|
2015-10-15 12:03:31 -04:00
|
|
|
gpu_mem[gpu_mem_id].scratch_aperture.limit =
|
2015-12-21 15:42:52 -05:00
|
|
|
PORT_UINT64_TO_VPTR(process_apertures[i].scratch_limit);
|
2015-10-15 12:03:31 -04:00
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
if (IS_CANONICAL_ADDR(process_apertures[i].gpuvm_limit)) {
|
2016-03-01 17:50:46 -05:00
|
|
|
uint64_t vm_alignment = get_vm_alignment(
|
|
|
|
|
gpu_mem[gpu_mem_id].device_id);
|
2015-10-15 12:03:31 -04:00
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
/* Set proper alignment for scratch backing aperture */
|
2016-01-13 14:24:42 -05:00
|
|
|
gpu_mem[gpu_mem_id].scratch_physical.align = vm_alignment;
|
2015-10-17 02:50:50 -04:00
|
|
|
|
2016-03-01 17:50:46 -05:00
|
|
|
/* Non-canonical per-ASIC GPUVM aperture does
|
2017-04-20 08:25:00 -04:00
|
|
|
* not exist on dGPUs in GPUVM64 address mode
|
|
|
|
|
*/
|
2016-03-01 17:50:46 -05:00
|
|
|
gpu_mem[gpu_mem_id].gpuvm_aperture.base = NULL;
|
|
|
|
|
gpu_mem[gpu_mem_id].gpuvm_aperture.limit = NULL;
|
2015-10-15 12:03:31 -04:00
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
/* Update SVM aperture limits and alignment */
|
|
|
|
|
if (process_apertures[i].gpuvm_base > svm_base)
|
|
|
|
|
svm_base = process_apertures[i].gpuvm_base;
|
|
|
|
|
if (process_apertures[i].gpuvm_limit < svm_limit ||
|
|
|
|
|
svm_limit == 0)
|
|
|
|
|
svm_limit = process_apertures[i].gpuvm_limit;
|
|
|
|
|
if (vm_alignment > svm_alignment)
|
|
|
|
|
svm_alignment = vm_alignment;
|
|
|
|
|
} else {
|
|
|
|
|
gpu_mem[gpu_mem_id].gpuvm_aperture.base =
|
|
|
|
|
PORT_UINT64_TO_VPTR(process_apertures[i].gpuvm_base);
|
|
|
|
|
gpu_mem[gpu_mem_id].gpuvm_aperture.limit =
|
|
|
|
|
PORT_UINT64_TO_VPTR(process_apertures[i].gpuvm_limit);
|
2018-08-04 15:58:23 -04:00
|
|
|
/* Reserve space at the start of the
|
|
|
|
|
* aperture. After subtracting the base, we
|
|
|
|
|
* don't want valid pointers to become NULL.
|
|
|
|
|
*/
|
|
|
|
|
aperture_allocate_area(
|
|
|
|
|
&gpu_mem[gpu_mem_id].gpuvm_aperture,
|
|
|
|
|
gpu_mem[gpu_mem_id].gpuvm_aperture.align);
|
2018-01-24 23:02:48 -05:00
|
|
|
}
|
2018-03-01 17:31:38 -05:00
|
|
|
|
|
|
|
|
/* Acquire the VM from the DRM render node for KFD use */
|
|
|
|
|
ret = acquire_vm(gpu_mem[gpu_mem_id].gpu_id,
|
|
|
|
|
gpu_mem[gpu_mem_id].drm_render_fd);
|
|
|
|
|
if (ret != HSAKMT_STATUS_SUCCESS)
|
|
|
|
|
goto acquire_vm_failed;
|
2018-01-24 23:02:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (svm_limit) {
|
|
|
|
|
/* At least one GPU uses GPUVM in canonical address
|
|
|
|
|
* space. Set up SVM apertures shared by all such GPUs
|
|
|
|
|
*/
|
|
|
|
|
ret = init_svm_apertures(svm_base, svm_limit, svm_alignment,
|
2018-08-10 17:05:42 -04:00
|
|
|
guardPages);
|
2018-01-24 23:02:48 -05:00
|
|
|
if (ret != HSAKMT_STATUS_SUCCESS)
|
|
|
|
|
goto init_svm_failed;
|
|
|
|
|
|
|
|
|
|
for (i = 0 ; i < num_of_nodes ; i++) {
|
|
|
|
|
uintptr_t alt_base;
|
|
|
|
|
uint64_t alt_size;
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
if (!IS_CANONICAL_ADDR(process_apertures[i].gpuvm_limit))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Set memory policy to match the SVM apertures */
|
2018-08-10 17:05:42 -04:00
|
|
|
alt_base = (uintptr_t)svm.dgpu_alt_aperture->base;
|
|
|
|
|
alt_size = VOID_PTRS_SUB(svm.dgpu_alt_aperture->limit,
|
|
|
|
|
svm.dgpu_alt_aperture->base) + 1;
|
2018-01-24 23:02:48 -05:00
|
|
|
err = fmm_set_memory_policy(process_apertures[i].gpu_id,
|
2018-08-10 17:05:42 -04:00
|
|
|
svm.disable_cache ?
|
2016-03-17 18:45:40 -04:00
|
|
|
KFD_IOC_CACHE_POLICY_COHERENT :
|
|
|
|
|
KFD_IOC_CACHE_POLICY_NONCOHERENT,
|
|
|
|
|
KFD_IOC_CACHE_POLICY_COHERENT,
|
|
|
|
|
alt_base, alt_size);
|
2018-01-24 23:02:48 -05:00
|
|
|
if (err) {
|
|
|
|
|
pr_err("Failed to set mem policy for GPU [0x%x]\n",
|
|
|
|
|
process_apertures[i].gpu_id);
|
2015-10-15 12:03:31 -04:00
|
|
|
ret = HSAKMT_STATUS_ERROR;
|
2015-09-09 14:41:49 +03:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-22 13:06:50 +02:00
|
|
|
}
|
2014-07-29 11:21:10 +03:00
|
|
|
|
2016-09-08 15:01:28 -04:00
|
|
|
cpuvm_aperture.align = PAGE_SIZE;
|
|
|
|
|
cpuvm_aperture.limit = (void *)0x7FFFFFFFFFFF; /* 2^47 - 1 */
|
|
|
|
|
|
2018-06-28 18:24:54 +08:00
|
|
|
fmm_init_rbtree();
|
|
|
|
|
|
2016-01-13 17:27:31 -05:00
|
|
|
free(process_apertures);
|
|
|
|
|
return ret;
|
|
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
init_svm_failed:
|
2018-03-01 17:31:38 -05:00
|
|
|
acquire_vm_failed:
|
2015-12-21 15:42:52 -05:00
|
|
|
get_aperture_ioctl_failed:
|
2017-04-20 08:25:00 -04:00
|
|
|
invalid_gpu_id:
|
2015-12-21 15:42:52 -05:00
|
|
|
free(process_apertures);
|
2016-01-13 17:27:31 -05:00
|
|
|
sysfs_parse_failed:
|
|
|
|
|
fmm_destroy_process_apertures();
|
2015-10-02 15:42:02 -04:00
|
|
|
return ret;
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
2016-01-13 17:27:31 -05:00
|
|
|
void fmm_destroy_process_apertures(void)
|
|
|
|
|
{
|
|
|
|
|
if (gpu_mem) {
|
|
|
|
|
free(gpu_mem);
|
|
|
|
|
gpu_mem = NULL;
|
|
|
|
|
}
|
|
|
|
|
gpu_mem_count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 21:32:41 -04:00
|
|
|
HSAKMT_STATUS fmm_get_aperture_base_and_limit(aperture_type_e aperture_type, HSAuint32 gpu_id,
|
|
|
|
|
HSAuint64 *aperture_base, HSAuint64 *aperture_limit)
|
2015-06-09 05:37:05 +03:00
|
|
|
{
|
2015-10-22 21:32:41 -04:00
|
|
|
HSAKMT_STATUS err = HSAKMT_STATUS_SUCCESS;
|
2015-06-09 05:37:05 +03:00
|
|
|
int32_t slot = gpu_mem_find_by_gpu_id(gpu_id);
|
|
|
|
|
|
|
|
|
|
if (slot < 0)
|
|
|
|
|
return HSAKMT_STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
|
|
switch (aperture_type) {
|
|
|
|
|
case FMM_GPUVM:
|
2015-10-22 21:32:41 -04:00
|
|
|
if (aperture_is_valid(gpu_mem[slot].gpuvm_aperture.base,
|
|
|
|
|
gpu_mem[slot].gpuvm_aperture.limit)) {
|
|
|
|
|
*aperture_base = PORT_VPTR_TO_UINT64(gpu_mem[slot].gpuvm_aperture.base);
|
|
|
|
|
*aperture_limit = PORT_VPTR_TO_UINT64(gpu_mem[slot].gpuvm_aperture.limit);
|
|
|
|
|
}
|
2015-06-09 05:37:05 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FMM_SCRATCH:
|
2015-10-22 21:32:41 -04:00
|
|
|
if (aperture_is_valid(gpu_mem[slot].scratch_aperture.base,
|
|
|
|
|
gpu_mem[slot].scratch_aperture.limit)) {
|
|
|
|
|
*aperture_base = PORT_VPTR_TO_UINT64(gpu_mem[slot].scratch_aperture.base);
|
|
|
|
|
*aperture_limit = PORT_VPTR_TO_UINT64(gpu_mem[slot].scratch_aperture.limit);
|
|
|
|
|
}
|
2015-06-09 05:37:05 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FMM_LDS:
|
2015-10-22 21:32:41 -04:00
|
|
|
if (aperture_is_valid(gpu_mem[slot].lds_aperture.base,
|
|
|
|
|
gpu_mem[slot].lds_aperture.limit)) {
|
|
|
|
|
*aperture_base = PORT_VPTR_TO_UINT64(gpu_mem[slot].lds_aperture.base);
|
|
|
|
|
*aperture_limit = PORT_VPTR_TO_UINT64(gpu_mem[slot].lds_aperture.limit);
|
|
|
|
|
}
|
2015-06-09 05:37:05 +03:00
|
|
|
break;
|
|
|
|
|
|
2016-03-09 14:29:37 -05:00
|
|
|
case FMM_SVM:
|
|
|
|
|
/* Report single SVM aperture, starting at base of
|
2017-04-20 08:25:00 -04:00
|
|
|
* fine-grained, ending at limit of coarse-grained
|
|
|
|
|
*/
|
2018-08-10 17:05:42 -04:00
|
|
|
if (aperture_is_valid(svm.dgpu_alt_aperture->base,
|
|
|
|
|
svm.dgpu_aperture->limit)) {
|
|
|
|
|
*aperture_base = PORT_VPTR_TO_UINT64(svm.dgpu_alt_aperture->base);
|
|
|
|
|
*aperture_limit = PORT_VPTR_TO_UINT64(svm.dgpu_aperture->limit);
|
2016-03-09 14:29:37 -05:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2015-06-09 05:37:05 +03:00
|
|
|
default:
|
2015-10-22 21:32:41 -04:00
|
|
|
err = HSAKMT_STATUS_ERROR;
|
2015-06-09 05:37:05 +03:00
|
|
|
}
|
2015-02-22 13:06:50 +02:00
|
|
|
|
2015-10-22 21:32:41 -04:00
|
|
|
return err;
|
2014-07-29 11:21:10 +03:00
|
|
|
}
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2017-11-30 10:56:38 -05:00
|
|
|
static bool id_in_array(uint32_t id, uint32_t *ids_array,
|
|
|
|
|
uint32_t ids_array_size)
|
|
|
|
|
{
|
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ids_array_size/sizeof(uint32_t); i++) {
|
|
|
|
|
if (id == ids_array[i])
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper function to remove ids_array from
|
|
|
|
|
* obj->mapped_device_id_array
|
|
|
|
|
*/
|
|
|
|
|
static void remove_device_ids_from_mapped_array(vm_object_t *obj,
|
|
|
|
|
uint32_t *ids_array, uint32_t ids_array_size)
|
|
|
|
|
{
|
|
|
|
|
uint32_t i = 0, j = 0;
|
|
|
|
|
|
|
|
|
|
if (obj->mapped_device_id_array == ids_array)
|
|
|
|
|
goto set_size_and_free;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < obj->mapped_device_id_array_size/
|
|
|
|
|
sizeof(uint32_t); i++) {
|
|
|
|
|
if (!id_in_array(obj->mapped_device_id_array[i],
|
|
|
|
|
ids_array, ids_array_size))
|
|
|
|
|
obj->mapped_device_id_array[j++] =
|
|
|
|
|
obj->mapped_device_id_array[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set_size_and_free:
|
|
|
|
|
obj->mapped_device_id_array_size = j*sizeof(uint32_t);
|
|
|
|
|
if (!j) {
|
|
|
|
|
if (obj->mapped_device_id_array)
|
|
|
|
|
free(obj->mapped_device_id_array);
|
|
|
|
|
|
|
|
|
|
obj->mapped_device_id_array = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper function to add ids_array to
|
|
|
|
|
* obj->mapped_device_id_array
|
|
|
|
|
*/
|
|
|
|
|
static void add_device_ids_to_mapped_array(vm_object_t *obj,
|
|
|
|
|
uint32_t *ids_array, uint32_t ids_array_size)
|
|
|
|
|
{
|
|
|
|
|
uint32_t new_array_size;
|
|
|
|
|
|
|
|
|
|
/* Remove any potential duplicated ids */
|
|
|
|
|
remove_device_ids_from_mapped_array(obj, ids_array, ids_array_size);
|
|
|
|
|
new_array_size = obj->mapped_device_id_array_size
|
|
|
|
|
+ ids_array_size;
|
|
|
|
|
|
|
|
|
|
obj->mapped_device_id_array = (uint32_t *)realloc(
|
|
|
|
|
obj->mapped_device_id_array, new_array_size);
|
|
|
|
|
|
|
|
|
|
memcpy(&obj->mapped_device_id_array
|
|
|
|
|
[obj->mapped_device_id_array_size/sizeof(uint32_t)],
|
|
|
|
|
ids_array, ids_array_size);
|
|
|
|
|
|
|
|
|
|
obj->mapped_device_id_array_size = new_array_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-08-15 17:13:55 -04:00
|
|
|
/* If nodes_to_map is not NULL, map the nodes specified; otherwise map all. */
|
2017-11-30 11:06:45 -05:00
|
|
|
static int _fmm_map_to_gpu(manageable_aperture_t *aperture,
|
2017-08-15 17:13:55 -04:00
|
|
|
void *address, uint64_t size, vm_object_t *obj,
|
|
|
|
|
uint32_t *nodes_to_map, uint32_t nodes_array_size)
|
2015-08-23 17:42:27 +03:00
|
|
|
{
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_map_memory_to_gpu_args args = {0};
|
2015-08-23 17:42:27 +03:00
|
|
|
vm_object_t *object;
|
2017-08-15 19:18:03 -04:00
|
|
|
int ret = 0;
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2016-02-24 17:30:48 +02:00
|
|
|
if (!obj)
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2016-02-24 17:30:48 +02:00
|
|
|
object = obj;
|
2015-08-23 17:42:27 +03:00
|
|
|
if (!object) {
|
2016-02-24 17:30:48 +02:00
|
|
|
/* Find the object to retrieve the handle */
|
2016-09-13 12:44:29 -04:00
|
|
|
object = vm_find_object_by_address(aperture, address, 0);
|
2017-08-15 19:18:03 -04:00
|
|
|
if (!object) {
|
|
|
|
|
ret = -EINVAL;
|
2016-02-24 17:30:48 +02:00
|
|
|
goto err_object_not_found;
|
2017-08-15 19:18:03 -04:00
|
|
|
}
|
2015-08-23 17:42:27 +03:00
|
|
|
}
|
|
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
/* For a memory region that is registered by user pointer, changing
|
|
|
|
|
* mapping nodes is not allowed, so we don't need to check the mapping
|
|
|
|
|
* nodes or map if it's already mapped. Just increase the reference.
|
|
|
|
|
*/
|
|
|
|
|
if (object->userptr && object->mapping_count) {
|
|
|
|
|
++object->mapping_count;
|
|
|
|
|
goto exit_ok;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-23 17:42:27 +03:00
|
|
|
args.handle = object->handle;
|
2017-08-15 17:13:55 -04:00
|
|
|
if (nodes_to_map) {
|
|
|
|
|
/* If specified, map the requested */
|
|
|
|
|
args.device_ids_array_ptr = (uint64_t)nodes_to_map;
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_devices = nodes_array_size / sizeof(uint32_t);
|
2017-08-15 17:13:55 -04:00
|
|
|
} else if (object->registered_device_id_array_size > 0) {
|
|
|
|
|
/* otherwise map all registered */
|
2017-05-01 19:19:38 -04:00
|
|
|
args.device_ids_array_ptr =
|
|
|
|
|
(uint64_t)object->registered_device_id_array;
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_devices = object->registered_device_id_array_size /
|
|
|
|
|
sizeof(uint32_t);
|
2016-02-24 17:30:48 +02:00
|
|
|
} else {
|
2017-08-15 17:13:55 -04:00
|
|
|
/* not specified, not registered: map all GPUs */
|
2017-05-01 19:19:38 -04:00
|
|
|
args.device_ids_array_ptr = (uint64_t)all_gpu_id_array;
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_devices = all_gpu_id_array_size / sizeof(uint32_t);
|
2016-01-07 16:28:20 -05:00
|
|
|
}
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_success = 0;
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2017-08-15 19:18:03 -04:00
|
|
|
ret = kmtIoctl(kfd_fd, AMDKFD_IOC_MAP_MEMORY_TO_GPU, &args);
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2017-11-30 10:56:38 -05:00
|
|
|
add_device_ids_to_mapped_array(object,
|
|
|
|
|
(uint32_t *)args.device_ids_array_ptr,
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_success * sizeof(uint32_t));
|
2017-11-30 10:56:38 -05:00
|
|
|
print_device_id_array((uint32_t *)object->mapped_device_id_array,
|
|
|
|
|
object->mapped_device_id_array_size);
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
object->mapping_count = 1;
|
2017-11-20 16:15:29 -05:00
|
|
|
/* Mapping changed and lifecycle of object->mapped_node_id_array
|
|
|
|
|
* terminates here. Free it and allocate on next query
|
|
|
|
|
*/
|
|
|
|
|
if (object->mapped_node_id_array) {
|
|
|
|
|
free(object->mapped_node_id_array);
|
|
|
|
|
object->mapped_node_id_array = NULL;
|
|
|
|
|
}
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
exit_ok:
|
2015-08-23 17:42:27 +03:00
|
|
|
err_object_not_found:
|
2016-02-24 17:30:48 +02:00
|
|
|
if (!obj)
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2017-08-15 19:18:03 -04:00
|
|
|
|
|
|
|
|
return ret;
|
2015-08-23 17:42:27 +03:00
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static int _fmm_map_to_gpu_scratch(uint32_t gpu_id, manageable_aperture_t *aperture,
|
2015-10-17 02:50:50 -04:00
|
|
|
void *address, uint64_t size)
|
|
|
|
|
{
|
|
|
|
|
int32_t gpu_mem_id;
|
|
|
|
|
int ret;
|
2015-12-20 15:01:13 +02:00
|
|
|
bool is_debugger = 0;
|
|
|
|
|
void *mmap_ret = NULL;
|
|
|
|
|
uint64_t mmap_offset = 0;
|
2018-06-20 13:30:06 +08:00
|
|
|
vm_object_t *obj;
|
2016-09-01 23:25:42 -04:00
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
/* Retrieve gpu_mem id according to gpu_id */
|
|
|
|
|
gpu_mem_id = gpu_mem_find_by_gpu_id(gpu_id);
|
|
|
|
|
if (gpu_mem_id < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!topology_is_dgpu(gpu_mem[gpu_mem_id].device_id))
|
2015-10-17 02:50:50 -04:00
|
|
|
return 0; /* Nothing to do on APU */
|
|
|
|
|
|
|
|
|
|
/* sanity check the address */
|
|
|
|
|
if (address < aperture->base ||
|
2017-04-20 08:25:00 -04:00
|
|
|
VOID_PTR_ADD(address, size - 1) > aperture->limit)
|
2015-10-17 02:50:50 -04:00
|
|
|
return -1;
|
|
|
|
|
|
2016-01-14 17:07:28 -05:00
|
|
|
ret = debug_get_reg_status(gpu_mem[gpu_mem_id].node_id, &is_debugger);
|
2015-10-17 02:50:50 -04:00
|
|
|
/* allocate object within the scratch backing aperture */
|
2016-01-14 17:07:28 -05:00
|
|
|
if (!ret && !is_debugger) {
|
2018-06-20 13:30:06 +08:00
|
|
|
obj = fmm_allocate_memory_object(
|
2017-08-15 19:18:03 -04:00
|
|
|
gpu_id, address, size, aperture, NULL,
|
|
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_VRAM |
|
|
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!obj)
|
2015-12-20 15:01:13 +02:00
|
|
|
return -1;
|
|
|
|
|
} else {
|
2017-10-27 16:17:51 -04:00
|
|
|
int map_fd = mmap_offset >= (1ULL<<40) ? kfd_fd :
|
2018-03-01 17:31:38 -05:00
|
|
|
gpu_mem[gpu_mem_id].drm_render_fd;
|
2018-06-20 13:30:06 +08:00
|
|
|
obj = fmm_allocate_memory_object(
|
2017-08-15 19:18:03 -04:00
|
|
|
gpu_id, address, size, aperture, &mmap_offset,
|
|
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_GTT |
|
|
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE);
|
2015-12-20 15:01:13 +02:00
|
|
|
mmap_ret = mmap(address, size,
|
|
|
|
|
PROT_READ | PROT_WRITE,
|
2017-10-27 16:17:51 -04:00
|
|
|
MAP_SHARED | MAP_FIXED, map_fd, mmap_offset);
|
2015-12-20 15:01:13 +02:00
|
|
|
if (mmap_ret == MAP_FAILED) {
|
2018-06-20 13:30:06 +08:00
|
|
|
__fmm_release(obj, aperture);
|
2015-12-20 15:01:13 +02:00
|
|
|
return -1;
|
|
|
|
|
}
|
2015-10-17 02:50:50 -04:00
|
|
|
}
|
|
|
|
|
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
/* map to GPU */
|
2017-11-30 11:06:45 -05:00
|
|
|
ret = _fmm_map_to_gpu(aperture, address, size, NULL, NULL, 0);
|
2015-10-17 02:50:50 -04:00
|
|
|
if (ret != 0)
|
2018-06-20 13:30:06 +08:00
|
|
|
__fmm_release(obj, aperture);
|
2015-10-17 02:50:50 -04:00
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-30 11:06:45 -05:00
|
|
|
static int _fmm_map_to_apu_local(uint32_t gpu_id,
|
|
|
|
|
manageable_aperture_t *aperture,
|
2015-02-22 13:06:50 +02:00
|
|
|
void *address, uint64_t size,
|
|
|
|
|
uint64_t *gpuvm_address)
|
|
|
|
|
{
|
2015-02-23 15:54:01 +02:00
|
|
|
vm_object_t *object;
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2017-11-30 11:06:45 -05:00
|
|
|
if (gpuvm_address)
|
|
|
|
|
*gpuvm_address = 0;
|
2015-02-22 13:06:50 +02:00
|
|
|
/* Check that address space was previously reserved */
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!vm_find(aperture, address))
|
2015-02-22 13:06:50 +02:00
|
|
|
return -1;
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2015-02-23 15:54:01 +02:00
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2015-02-23 15:54:01 +02:00
|
|
|
/* Find the object to retrieve the handle */
|
2016-09-13 12:44:29 -04:00
|
|
|
object = vm_find_object_by_address(aperture, address, 0);
|
2017-11-30 11:06:45 -05:00
|
|
|
if (!object) {
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return -1;
|
2017-11-29 09:31:35 -05:00
|
|
|
}
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2017-11-27 18:13:08 -05:00
|
|
|
|
2017-11-30 11:06:45 -05:00
|
|
|
if (_fmm_map_to_gpu(aperture, address, size, object, NULL, 0))
|
|
|
|
|
return -1;
|
|
|
|
|
|
2015-09-09 14:41:49 +03:00
|
|
|
if (gpuvm_address) {
|
|
|
|
|
*gpuvm_address = (uint64_t)object->start;
|
|
|
|
|
if (!topology_is_dgpu(get_device_id_by_gpu_id(gpu_id)))
|
|
|
|
|
*gpuvm_address = VOID_PTRS_SUB(object->start, aperture->base);
|
|
|
|
|
}
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
return 0;
|
2014-10-13 11:29:39 +03:00
|
|
|
}
|
|
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
static int _fmm_map_to_gpu_userptr(void *addr, uint64_t size,
|
2016-02-24 17:30:48 +02:00
|
|
|
uint64_t *gpuvm_addr, vm_object_t *object)
|
2015-11-06 18:28:30 -05:00
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
vm_object_t *obj;
|
|
|
|
|
void *svm_addr;
|
|
|
|
|
HSAuint64 svm_size;
|
|
|
|
|
HSAuint32 page_offset = (HSAuint64)addr & (PAGE_SIZE-1);
|
|
|
|
|
int ret;
|
|
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
|
|
|
|
|
/* Find the start address in SVM space for GPU mapping */
|
2016-02-24 17:30:48 +02:00
|
|
|
if (!object)
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
obj = object;
|
|
|
|
|
if (!obj) {
|
2016-11-09 14:54:17 -05:00
|
|
|
obj = vm_find_object_by_userptr(aperture, addr, size);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!obj) {
|
2016-02-24 17:30:48 +02:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
}
|
2015-11-06 18:28:30 -05:00
|
|
|
}
|
|
|
|
|
svm_addr = obj->start;
|
|
|
|
|
svm_size = obj->size;
|
|
|
|
|
|
|
|
|
|
/* Map and return the GPUVM address adjusted by the offset
|
2017-04-20 08:25:00 -04:00
|
|
|
* from the start of the page
|
|
|
|
|
*/
|
2017-11-30 11:06:45 -05:00
|
|
|
ret = _fmm_map_to_gpu(aperture, svm_addr, svm_size, obj, NULL, 0);
|
2015-11-06 18:28:30 -05:00
|
|
|
if (ret == 0 && gpuvm_addr)
|
|
|
|
|
*gpuvm_addr = (uint64_t)svm_addr + page_offset;
|
|
|
|
|
|
2016-02-24 17:30:48 +02:00
|
|
|
if (!object)
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
int fmm_map_to_gpu(void *address, uint64_t size, uint64_t *gpuvm_address)
|
|
|
|
|
{
|
2016-01-13 17:27:31 -05:00
|
|
|
uint32_t i;
|
2014-10-13 11:29:39 +03:00
|
|
|
uint64_t pi;
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/* Find an aperture the requested address belongs to */
|
2016-01-13 17:27:31 -05:00
|
|
|
for (i = 0; i < gpu_mem_count; i++) {
|
2015-02-22 13:06:50 +02:00
|
|
|
if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID)
|
|
|
|
|
continue;
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
if ((address >= gpu_mem[i].scratch_physical.base) &&
|
|
|
|
|
(address <= gpu_mem[i].scratch_physical.limit))
|
|
|
|
|
return _fmm_map_to_gpu_scratch(gpu_mem[i].gpu_id,
|
2015-11-25 18:00:42 -05:00
|
|
|
&gpu_mem[i].scratch_physical,
|
|
|
|
|
address, size);
|
2015-10-17 02:50:50 -04:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
if ((address >= gpu_mem[i].gpuvm_aperture.base) &&
|
|
|
|
|
(address <= gpu_mem[i].gpuvm_aperture.limit))
|
|
|
|
|
/* map it */
|
2017-11-30 11:06:45 -05:00
|
|
|
return _fmm_map_to_apu_local(gpu_mem[i].gpu_id,
|
2015-02-22 13:06:50 +02:00
|
|
|
&gpu_mem[i].gpuvm_aperture,
|
|
|
|
|
address, size, gpuvm_address);
|
2015-11-25 18:00:42 -05:00
|
|
|
}
|
|
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
if ((address >= svm.dgpu_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_aperture->limit))
|
2015-11-25 18:00:42 -05:00
|
|
|
/* map it */
|
2018-08-10 17:05:42 -04:00
|
|
|
return _fmm_map_to_gpu(svm.dgpu_aperture,
|
2017-08-15 17:13:55 -04:00
|
|
|
address, size, NULL, NULL, 0);
|
2018-08-10 17:05:42 -04:00
|
|
|
else if ((address >= svm.dgpu_alt_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_alt_aperture->limit))
|
2015-11-25 18:00:42 -05:00
|
|
|
/* map it */
|
2018-08-10 17:05:42 -04:00
|
|
|
return _fmm_map_to_gpu(svm.dgpu_alt_aperture,
|
2017-08-15 17:13:55 -04:00
|
|
|
address, size, NULL, NULL, 0);
|
2015-11-25 18:00:42 -05:00
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
/*
|
|
|
|
|
* If address isn't an SVM memory address, we assume that this
|
|
|
|
|
* is system memory address. On dGPU we need to map it,
|
|
|
|
|
* assuming it was previously registered.
|
|
|
|
|
*/
|
|
|
|
|
if (is_dgpu)
|
|
|
|
|
/* TODO: support mixed APU and dGPU configurations */
|
2016-02-24 17:30:48 +02:00
|
|
|
return _fmm_map_to_gpu_userptr(address, size, gpuvm_address, NULL);
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/*
|
2015-11-06 18:28:30 -05:00
|
|
|
* On an APU a system memory address is accessed through
|
|
|
|
|
* IOMMU. Thus we "prefetch" it.
|
2015-02-22 13:06:50 +02:00
|
|
|
*/
|
|
|
|
|
for (pi = 0; pi < size / PAGE_SIZE; pi++)
|
|
|
|
|
((char *) address)[pi * PAGE_SIZE] = 0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2016-02-24 17:30:48 +02:00
|
|
|
static void print_device_id_array(uint32_t *device_id_array, uint32_t device_id_array_size)
|
|
|
|
|
{
|
|
|
|
|
#ifdef DEBUG_PRINT_APERTURE
|
|
|
|
|
device_id_array_size /= sizeof(uint32_t);
|
|
|
|
|
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("device id array size %d\n", device_id_array_size);
|
2016-02-24 17:30:48 +02:00
|
|
|
|
|
|
|
|
for (uint32_t i = 0 ; i < device_id_array_size; i++)
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_info("%d . 0x%x\n", (i+1), device_id_array[i]);
|
2016-02-24 17:30:48 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static int _fmm_unmap_from_gpu(manageable_aperture_t *aperture, void *address,
|
2016-02-24 17:30:48 +02:00
|
|
|
uint32_t *device_ids_array, uint32_t device_ids_array_size,
|
|
|
|
|
vm_object_t *obj)
|
2015-02-22 13:06:50 +02:00
|
|
|
{
|
|
|
|
|
vm_object_t *object;
|
2016-11-09 14:54:17 -05:00
|
|
|
int ret = 0;
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_unmap_memory_from_gpu_args args = {0};
|
2016-11-09 14:54:17 -05:00
|
|
|
HSAuint32 page_offset = (HSAint64)address & (PAGE_SIZE - 1);
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2016-02-24 17:30:48 +02:00
|
|
|
if (!obj)
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/* Find the object to retrieve the handle */
|
2016-02-24 17:30:48 +02:00
|
|
|
object = obj;
|
|
|
|
|
if (!object) {
|
2016-11-09 14:54:17 -05:00
|
|
|
object = vm_find_object_by_address(aperture,
|
|
|
|
|
VOID_PTR_SUB(address, page_offset), 0);
|
2016-02-24 17:30:48 +02:00
|
|
|
if (!object) {
|
|
|
|
|
ret = -1;
|
2016-11-09 14:54:17 -05:00
|
|
|
goto out;
|
2016-02-24 17:30:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
if (object->userptr && object->mapping_count > 1) {
|
|
|
|
|
--object->mapping_count;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-13 11:29:39 +03:00
|
|
|
args.handle = object->handle;
|
2016-02-24 17:30:48 +02:00
|
|
|
if (device_ids_array && device_ids_array_size > 0) {
|
2017-05-01 19:19:38 -04:00
|
|
|
args.device_ids_array_ptr = (uint64_t)device_ids_array;
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_devices = device_ids_array_size / sizeof(uint32_t);
|
2016-02-24 17:30:48 +02:00
|
|
|
} else if (object->mapped_device_id_array_size > 0) {
|
2017-05-01 19:19:38 -04:00
|
|
|
args.device_ids_array_ptr = (uint64_t)object->mapped_device_id_array;
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_devices = object->mapped_device_id_array_size /
|
|
|
|
|
sizeof(uint32_t);
|
2016-01-07 16:28:20 -05:00
|
|
|
} else {
|
2016-02-24 17:30:48 +02:00
|
|
|
/*
|
|
|
|
|
* When unmap exits here it should return failing error code as the user tried to
|
|
|
|
|
* unmap already unmapped buffer. Currently we returns success as KFDTEST and RT
|
|
|
|
|
* need to deploy the change on there side before thunk fails on this case.
|
|
|
|
|
*/
|
|
|
|
|
ret = 0;
|
2016-11-09 14:54:17 -05:00
|
|
|
goto out;
|
2016-01-07 16:28:20 -05:00
|
|
|
}
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_success = 0;
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2017-05-01 19:19:38 -04:00
|
|
|
print_device_id_array((void *)args.device_ids_array_ptr,
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_devices * sizeof(uint32_t));
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2017-05-01 19:19:38 -04:00
|
|
|
ret = kmtIoctl(kfd_fd, AMDKFD_IOC_UNMAP_MEMORY_FROM_GPU, &args);
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2017-11-30 10:56:38 -05:00
|
|
|
remove_device_ids_from_mapped_array(object,
|
|
|
|
|
(uint32_t *)args.device_ids_array_ptr,
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_success * sizeof(uint32_t));
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2016-09-01 23:25:42 -04:00
|
|
|
if (object->mapped_node_id_array)
|
|
|
|
|
free(object->mapped_node_id_array);
|
|
|
|
|
object->mapped_node_id_array = NULL;
|
2016-11-09 14:54:17 -05:00
|
|
|
object->mapping_count = 0;
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
out:
|
2016-02-24 17:30:48 +02:00
|
|
|
if (!obj)
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return ret;
|
2014-10-13 11:29:39 +03:00
|
|
|
}
|
|
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
static int _fmm_unmap_from_gpu_scratch(uint32_t gpu_id,
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture,
|
2015-10-17 02:50:50 -04:00
|
|
|
void *address)
|
|
|
|
|
{
|
|
|
|
|
int32_t gpu_mem_id;
|
|
|
|
|
vm_object_t *object;
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_unmap_memory_from_gpu_args args = {0};
|
2017-08-15 19:18:03 -04:00
|
|
|
int ret;
|
2015-10-17 02:50:50 -04:00
|
|
|
|
|
|
|
|
/* Retrieve gpu_mem id according to gpu_id */
|
|
|
|
|
gpu_mem_id = gpu_mem_find_by_gpu_id(gpu_id);
|
|
|
|
|
if (gpu_mem_id < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!topology_is_dgpu(gpu_mem[gpu_mem_id].device_id))
|
2015-10-17 02:50:50 -04:00
|
|
|
return 0; /* Nothing to do on APU */
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
/* Find the object to retrieve the handle and size */
|
2016-09-13 12:44:29 -04:00
|
|
|
object = vm_find_object_by_address(aperture, address, 0);
|
2017-08-15 19:18:03 -04:00
|
|
|
if (!object) {
|
|
|
|
|
ret = -EINVAL;
|
2015-10-17 02:50:50 -04:00
|
|
|
goto err;
|
2017-08-15 19:18:03 -04:00
|
|
|
}
|
2015-10-17 02:50:50 -04:00
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!object->mapped_device_id_array ||
|
2016-02-24 17:30:48 +02:00
|
|
|
object->mapped_device_id_array_size == 0) {
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
/* unmap from GPU */
|
|
|
|
|
args.handle = object->handle;
|
2017-05-01 19:19:38 -04:00
|
|
|
args.device_ids_array_ptr = (uint64_t)object->mapped_device_id_array;
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_devices = object->mapped_device_id_array_size / sizeof(uint32_t);
|
|
|
|
|
args.n_success = 0;
|
|
|
|
|
ret = kmtIoctl(kfd_fd, AMDKFD_IOC_UNMAP_MEMORY_FROM_GPU, &args);
|
2015-10-17 02:50:50 -04:00
|
|
|
|
2017-11-30 10:56:38 -05:00
|
|
|
remove_device_ids_from_mapped_array(object,
|
|
|
|
|
(uint32_t *)args.device_ids_array_ptr,
|
2017-08-15 19:18:03 -04:00
|
|
|
args.n_success * sizeof(uint32_t));
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2016-09-01 23:25:42 -04:00
|
|
|
if (object->mapped_node_id_array)
|
|
|
|
|
free(object->mapped_node_id_array);
|
|
|
|
|
object->mapped_node_id_array = NULL;
|
2016-02-24 17:30:48 +02:00
|
|
|
|
2017-08-15 19:18:03 -04:00
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
/* free object in scratch backing aperture */
|
2018-06-20 13:30:06 +08:00
|
|
|
__fmm_release(object, aperture);
|
2015-10-17 02:50:50 -04:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2017-08-15 19:18:03 -04:00
|
|
|
return ret;
|
2015-10-17 02:50:50 -04:00
|
|
|
}
|
|
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
static int _fmm_unmap_from_gpu_userptr(void *addr)
|
|
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
vm_object_t *obj;
|
|
|
|
|
void *svm_addr;
|
|
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
|
|
|
|
|
/* Find the start address in SVM space for GPU unmapping */
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2016-11-09 14:54:17 -05:00
|
|
|
obj = vm_find_object_by_userptr(aperture, addr, 0);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!obj) {
|
2015-11-06 18:28:30 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
svm_addr = obj->start;
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
/* Unmap */
|
2016-02-24 17:30:48 +02:00
|
|
|
return _fmm_unmap_from_gpu(aperture, svm_addr, NULL, 0, NULL);
|
2015-11-06 18:28:30 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
int fmm_unmap_from_gpu(void *address)
|
|
|
|
|
{
|
2016-01-13 17:27:31 -05:00
|
|
|
uint32_t i;
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
/* Find the aperture the requested address belongs to */
|
2016-01-13 17:27:31 -05:00
|
|
|
for (i = 0; i < gpu_mem_count; i++) {
|
2015-02-22 13:06:50 +02:00
|
|
|
if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID)
|
|
|
|
|
continue;
|
|
|
|
|
|
2015-10-17 02:50:50 -04:00
|
|
|
if ((address >= gpu_mem[i].scratch_physical.base) &&
|
|
|
|
|
(address <= gpu_mem[i].scratch_physical.limit))
|
|
|
|
|
return _fmm_unmap_from_gpu_scratch(gpu_mem[i].gpu_id,
|
2015-11-25 18:00:42 -05:00
|
|
|
&gpu_mem[i].scratch_physical,
|
|
|
|
|
address);
|
2015-10-17 02:50:50 -04:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
if ((address >= gpu_mem[i].gpuvm_aperture.base) &&
|
|
|
|
|
(address <= gpu_mem[i].gpuvm_aperture.limit))
|
|
|
|
|
/* unmap it */
|
|
|
|
|
return _fmm_unmap_from_gpu(&gpu_mem[i].gpuvm_aperture,
|
2016-02-24 17:30:48 +02:00
|
|
|
address, NULL, 0, NULL);
|
2015-11-25 18:00:42 -05:00
|
|
|
}
|
|
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
if ((address >= svm.dgpu_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_aperture->limit))
|
2015-11-25 18:00:42 -05:00
|
|
|
/* unmap it */
|
2018-08-10 17:05:42 -04:00
|
|
|
return _fmm_unmap_from_gpu(svm.dgpu_aperture,
|
2016-02-24 17:30:48 +02:00
|
|
|
address, NULL, 0, NULL);
|
2018-08-10 17:05:42 -04:00
|
|
|
else if ((address >= svm.dgpu_alt_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_alt_aperture->limit))
|
2015-11-25 18:00:42 -05:00
|
|
|
/* unmap it */
|
2018-08-10 17:05:42 -04:00
|
|
|
return _fmm_unmap_from_gpu(svm.dgpu_alt_aperture,
|
2016-02-24 17:30:48 +02:00
|
|
|
address, NULL, 0, NULL);
|
2015-11-25 18:00:42 -05:00
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
/*
|
|
|
|
|
* If address isn't an SVM address, we assume that this is
|
|
|
|
|
* system memory address.
|
|
|
|
|
*/
|
|
|
|
|
if (is_dgpu)
|
|
|
|
|
/* TODO: support mixed APU and dGPU configurations */
|
|
|
|
|
return _fmm_unmap_from_gpu_userptr(address);
|
2014-10-13 11:29:39 +03:00
|
|
|
|
2015-02-22 13:06:50 +02:00
|
|
|
return 0;
|
2014-10-13 11:29:39 +03:00
|
|
|
}
|
2015-08-23 17:42:27 +03:00
|
|
|
|
|
|
|
|
bool fmm_get_handle(void *address, uint64_t *handle)
|
|
|
|
|
{
|
2016-01-13 17:27:31 -05:00
|
|
|
uint32_t i;
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2015-08-23 17:42:27 +03:00
|
|
|
vm_object_t *object;
|
|
|
|
|
bool found;
|
|
|
|
|
|
|
|
|
|
found = false;
|
|
|
|
|
aperture = NULL;
|
|
|
|
|
|
|
|
|
|
/* Find the aperture the requested address belongs to */
|
2016-01-13 17:27:31 -05:00
|
|
|
for (i = 0; i < gpu_mem_count; i++) {
|
2015-08-23 17:42:27 +03:00
|
|
|
if (gpu_mem[i].gpu_id == NON_VALID_GPU_ID)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if ((address >= gpu_mem[i].gpuvm_aperture.base) &&
|
|
|
|
|
(address <= gpu_mem[i].gpuvm_aperture.limit)) {
|
|
|
|
|
aperture = &gpu_mem[i].gpuvm_aperture;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-11-25 18:00:42 -05:00
|
|
|
}
|
2015-08-23 17:42:27 +03:00
|
|
|
|
2015-11-25 18:00:42 -05:00
|
|
|
if (!aperture) {
|
2018-08-10 17:05:42 -04:00
|
|
|
if ((address >= svm.dgpu_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_aperture->limit)) {
|
|
|
|
|
aperture = svm.dgpu_aperture;
|
|
|
|
|
} else if ((address >= svm.dgpu_alt_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_alt_aperture->limit)) {
|
|
|
|
|
aperture = svm.dgpu_alt_aperture;
|
2015-10-02 15:42:02 -04:00
|
|
|
}
|
2015-08-23 17:42:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!aperture)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
/* Find the object to retrieve the handle */
|
2016-09-13 12:44:29 -04:00
|
|
|
object = vm_find_object_by_address(aperture, address, 0);
|
2015-08-23 17:42:27 +03:00
|
|
|
if (object && handle) {
|
|
|
|
|
*handle = object->handle;
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return found;
|
|
|
|
|
}
|
2015-12-01 14:41:59 -05:00
|
|
|
|
2017-04-05 17:22:36 -04:00
|
|
|
static HSAuint8 fmm_check_user_memory(const void *addr, HSAuint64 size)
|
|
|
|
|
{
|
|
|
|
|
volatile const HSAuint8 *ptr = addr;
|
|
|
|
|
volatile const HSAuint8 *end = ptr + size;
|
|
|
|
|
HSAuint8 sum = 0;
|
|
|
|
|
|
|
|
|
|
/* Access every page in the buffer to make sure the mapping is
|
|
|
|
|
* valid. If it's not, it will die with a segfault that's easy
|
|
|
|
|
* to debug.
|
|
|
|
|
*/
|
|
|
|
|
for (; ptr < end; ptr = (void *)PAGE_ALIGN_UP(ptr + 1))
|
|
|
|
|
sum += *ptr;
|
|
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
static HSAKMT_STATUS fmm_register_user_memory(void *addr, HSAuint64 size, vm_object_t **obj_ret)
|
|
|
|
|
{
|
|
|
|
|
HSAuint32 gpu_id;
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
void *svm_addr = NULL;
|
|
|
|
|
vm_object_t *obj;
|
|
|
|
|
HSAuint32 page_offset = (HSAuint64)addr & (PAGE_SIZE-1);
|
|
|
|
|
HSAuint64 aligned_addr = (HSAuint64)addr - page_offset;
|
|
|
|
|
HSAuint64 aligned_size = PAGE_ALIGN_UP(page_offset + size);
|
|
|
|
|
|
2018-08-03 03:01:22 -04:00
|
|
|
/* Find first GPU for creating the userptr BO */
|
|
|
|
|
if (!g_first_gpu_mem)
|
2015-11-06 18:28:30 -05:00
|
|
|
return HSAKMT_STATUS_ERROR;
|
2018-08-03 03:01:22 -04:00
|
|
|
|
|
|
|
|
gpu_id = g_first_gpu_mem->gpu_id;
|
|
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
|
|
|
|
|
/* Check if this address was already registered */
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2016-11-09 14:54:17 -05:00
|
|
|
obj = vm_find_object_by_userptr(aperture, addr, size);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (obj) {
|
2016-11-09 14:54:17 -05:00
|
|
|
++obj->registration_count;
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
*obj_ret = obj;
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
2015-11-06 18:28:30 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
2017-04-05 17:22:36 -04:00
|
|
|
/* Optionally check that the CPU mapping is valid */
|
|
|
|
|
if (svm.check_userptr)
|
|
|
|
|
fmm_check_user_memory(addr, size);
|
|
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
/* Allocate BO, userptr address is passed in mmap_offset */
|
2018-08-04 15:58:23 -04:00
|
|
|
svm_addr = __fmm_allocate_device(gpu_id, aligned_size, aperture,
|
2017-05-26 16:12:09 -04:00
|
|
|
&aligned_addr, KFD_IOC_ALLOC_MEM_FLAGS_USERPTR |
|
2017-08-15 19:18:03 -04:00
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE |
|
|
|
|
|
KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE, &obj);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!svm_addr)
|
2015-11-06 18:28:30 -05:00
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
|
2016-09-01 23:25:42 -04:00
|
|
|
if (obj) {
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
obj->userptr = addr;
|
|
|
|
|
gpuid_to_nodeid(gpu_id, &obj->node_id);
|
|
|
|
|
obj->userptr_size = size;
|
2016-11-09 14:54:17 -05:00
|
|
|
obj->registration_count = 1;
|
2018-06-28 18:24:54 +08:00
|
|
|
obj->user_node.key = rbtree_key((unsigned long)addr, size);
|
|
|
|
|
rbtree_insert(&aperture->user_tree, &obj->user_node);
|
2015-11-06 18:28:30 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2017-04-20 08:25:00 -04:00
|
|
|
} else
|
2016-09-01 23:25:42 -04:00
|
|
|
return HSAKMT_STATUS_ERROR;
|
2015-11-06 18:28:30 -05:00
|
|
|
|
|
|
|
|
if (obj_ret)
|
|
|
|
|
*obj_ret = obj;
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HSAKMT_STATUS fmm_register_memory(void *address, uint64_t size_in_bytes,
|
2016-01-07 16:28:20 -05:00
|
|
|
uint32_t *gpu_id_array,
|
|
|
|
|
uint32_t gpu_id_array_size)
|
2015-12-23 17:23:25 +02:00
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2016-01-07 16:28:20 -05:00
|
|
|
vm_object_t *object = NULL;
|
2015-11-06 18:28:30 -05:00
|
|
|
HSAKMT_STATUS ret;
|
2016-01-07 16:28:20 -05:00
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
if (gpu_id_array_size > 0 && !gpu_id_array)
|
2016-01-07 16:28:20 -05:00
|
|
|
return HSAKMT_STATUS_INVALID_PARAMETER;
|
2015-12-23 17:23:25 +02:00
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
if ((address >= svm.dgpu_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_aperture->limit))
|
|
|
|
|
aperture = svm.dgpu_aperture;
|
|
|
|
|
else if ((address >= svm.dgpu_alt_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_alt_aperture->limit))
|
|
|
|
|
aperture = svm.dgpu_alt_aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
else {
|
|
|
|
|
/*
|
|
|
|
|
* If address isn't SVM address, we assume that this
|
|
|
|
|
* is system memory address.
|
|
|
|
|
*/
|
|
|
|
|
ret = fmm_register_user_memory(address, size_in_bytes, &object);
|
|
|
|
|
if (ret != HSAKMT_STATUS_SUCCESS)
|
|
|
|
|
return ret;
|
|
|
|
|
if (gpu_id_array_size == 0)
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
/* fall through */
|
|
|
|
|
}
|
2015-12-23 17:23:25 +02:00
|
|
|
|
2017-11-20 16:15:29 -05:00
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
if (!object)
|
2016-09-13 12:44:29 -04:00
|
|
|
object = vm_find_object_by_address(aperture, address, 0);
|
2017-11-20 16:15:29 -05:00
|
|
|
|
|
|
|
|
if (!object) {
|
2015-12-23 17:23:25 +02:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2017-11-20 16:15:29 -05:00
|
|
|
return HSAKMT_STATUS_NOT_SUPPORTED;
|
2015-12-23 17:23:25 +02:00
|
|
|
}
|
|
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
if (object->registered_device_id_array_size > 0) {
|
|
|
|
|
/* Multiple registration is allowed, but not changing nodes */
|
|
|
|
|
if ((gpu_id_array_size != object->registered_device_id_array_size)
|
|
|
|
|
|| memcmp(object->registered_device_id_array,
|
|
|
|
|
gpu_id_array, gpu_id_array_size)) {
|
2017-06-27 16:42:18 -04:00
|
|
|
pr_err("Cannot change nodes in a registered addr.\n");
|
2017-11-20 16:15:29 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2016-11-09 14:54:17 -05:00
|
|
|
return HSAKMT_STATUS_MEMORY_ALREADY_REGISTERED;
|
2017-08-21 19:58:35 -04:00
|
|
|
} else {
|
|
|
|
|
/* Delete the new array, keep the existing one. */
|
|
|
|
|
if (gpu_id_array)
|
|
|
|
|
free(gpu_id_array);
|
|
|
|
|
|
2017-11-20 16:15:29 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2016-11-09 14:54:17 -05:00
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
2017-08-21 19:58:35 -04:00
|
|
|
}
|
2016-11-09 14:54:17 -05:00
|
|
|
}
|
2015-12-23 17:23:25 +02:00
|
|
|
|
2016-01-07 16:28:20 -05:00
|
|
|
if (gpu_id_array_size > 0) {
|
2016-02-24 17:30:48 +02:00
|
|
|
object->registered_device_id_array = gpu_id_array;
|
|
|
|
|
object->registered_device_id_array_size = gpu_id_array_size;
|
2017-11-20 16:15:29 -05:00
|
|
|
/* Registration of object changed. Lifecycle of object->
|
|
|
|
|
* registered_node_id_array terminates here. Free old one
|
|
|
|
|
* and re-allocate on next query
|
|
|
|
|
*/
|
|
|
|
|
if (object->registered_node_id_array) {
|
|
|
|
|
free(object->registered_node_id_array);
|
|
|
|
|
object->registered_node_id_array = NULL;
|
|
|
|
|
}
|
2016-01-07 16:28:20 -05:00
|
|
|
}
|
2015-12-23 17:23:25 +02:00
|
|
|
|
2017-11-20 16:15:29 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2016-01-07 16:28:20 -05:00
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
2015-12-23 17:23:25 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-05 01:12:40 -05:00
|
|
|
#define GRAPHICS_METADATA_DEFAULT_SIZE 64
|
|
|
|
|
HSAKMT_STATUS fmm_register_graphics_handle(HSAuint64 GraphicsResourceHandle,
|
|
|
|
|
HsaGraphicsResourceInfo *GraphicsResourceInfo,
|
|
|
|
|
uint32_t *gpu_id_array,
|
|
|
|
|
uint32_t gpu_id_array_size)
|
|
|
|
|
{
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_get_dmabuf_info_args infoArgs = {0};
|
|
|
|
|
struct kfd_ioctl_import_dmabuf_args importArgs = {0};
|
|
|
|
|
struct kfd_ioctl_free_memory_of_gpu_args freeArgs = {0};
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2016-03-05 01:12:40 -05:00
|
|
|
vm_object_t *obj;
|
|
|
|
|
void *metadata;
|
|
|
|
|
void *mem, *aperture_base;
|
|
|
|
|
int32_t gpu_mem_id;
|
|
|
|
|
int r;
|
|
|
|
|
HSAKMT_STATUS status = HSAKMT_STATUS_ERROR;
|
2017-07-20 21:03:31 -04:00
|
|
|
static const uint64_t IMAGE_ALIGN = 256*1024;
|
2016-03-05 01:12:40 -05:00
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
if (gpu_id_array_size > 0 && !gpu_id_array)
|
2016-11-22 14:35:35 -05:00
|
|
|
return HSAKMT_STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
2016-03-05 01:12:40 -05:00
|
|
|
infoArgs.dmabuf_fd = GraphicsResourceHandle;
|
|
|
|
|
infoArgs.metadata_size = GRAPHICS_METADATA_DEFAULT_SIZE;
|
|
|
|
|
metadata = calloc(infoArgs.metadata_size, 1);
|
|
|
|
|
if (!metadata)
|
|
|
|
|
return HSAKMT_STATUS_NO_MEMORY;
|
|
|
|
|
infoArgs.metadata_ptr = (uint64_t)metadata;
|
|
|
|
|
r = kmtIoctl(kfd_fd, AMDKFD_IOC_GET_DMABUF_INFO, (void *)&infoArgs);
|
|
|
|
|
if (r && infoArgs.metadata_size > GRAPHICS_METADATA_DEFAULT_SIZE) {
|
|
|
|
|
/* Try again with bigger metadata */
|
|
|
|
|
free(metadata);
|
|
|
|
|
metadata = calloc(infoArgs.metadata_size, 1);
|
|
|
|
|
if (!metadata)
|
|
|
|
|
return HSAKMT_STATUS_NO_MEMORY;
|
|
|
|
|
infoArgs.metadata_ptr = (uint64_t)metadata;
|
|
|
|
|
r = kmtIoctl(kfd_fd, AMDKFD_IOC_GET_DMABUF_INFO, (void *)&infoArgs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r)
|
|
|
|
|
goto error_free_metadata;
|
|
|
|
|
|
|
|
|
|
/* Choose aperture based on GPU and allocate virtual address */
|
|
|
|
|
gpu_mem_id = gpu_mem_find_by_gpu_id(infoArgs.gpu_id);
|
|
|
|
|
if (gpu_mem_id < 0)
|
|
|
|
|
goto error_free_metadata;
|
2017-09-27 16:53:57 -04:00
|
|
|
if (topology_is_svm_needed(gpu_mem[gpu_mem_id].device_id)) {
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2016-03-05 01:12:40 -05:00
|
|
|
aperture_base = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
aperture = &gpu_mem[gpu_mem_id].gpuvm_aperture;
|
|
|
|
|
aperture_base = aperture->base;
|
|
|
|
|
}
|
|
|
|
|
if (!aperture_is_valid(aperture->base, aperture->limit))
|
|
|
|
|
goto error_free_metadata;
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2018-08-04 15:58:23 -04:00
|
|
|
mem = aperture_allocate_area_aligned(aperture, infoArgs.size,
|
2017-07-17 11:16:10 -04:00
|
|
|
MAX(aperture->align, IMAGE_ALIGN));
|
2016-03-05 01:12:40 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!mem)
|
2016-03-05 01:12:40 -05:00
|
|
|
goto error_free_metadata;
|
|
|
|
|
|
|
|
|
|
/* Import DMA buffer */
|
|
|
|
|
importArgs.va_addr = VOID_PTRS_SUB(mem, aperture_base);
|
|
|
|
|
importArgs.gpu_id = infoArgs.gpu_id;
|
|
|
|
|
importArgs.dmabuf_fd = GraphicsResourceHandle;
|
|
|
|
|
r = kmtIoctl(kfd_fd, AMDKFD_IOC_IMPORT_DMABUF, (void *)&importArgs);
|
|
|
|
|
if (r)
|
|
|
|
|
goto error_release_aperture;
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
obj = aperture_allocate_object(aperture, mem, importArgs.handle,
|
|
|
|
|
infoArgs.size, infoArgs.flags);
|
|
|
|
|
if (obj) {
|
|
|
|
|
obj->metadata = metadata;
|
|
|
|
|
obj->registered_device_id_array = gpu_id_array;
|
|
|
|
|
obj->registered_device_id_array_size = gpu_id_array_size;
|
2016-09-01 23:25:42 -04:00
|
|
|
gpuid_to_nodeid(infoArgs.gpu_id, &obj->node_id);
|
2016-03-05 01:12:40 -05:00
|
|
|
}
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
if (!obj)
|
|
|
|
|
goto error_release_buffer;
|
|
|
|
|
|
|
|
|
|
GraphicsResourceInfo->MemoryAddress = mem;
|
|
|
|
|
GraphicsResourceInfo->SizeInBytes = infoArgs.size;
|
|
|
|
|
GraphicsResourceInfo->Metadata = (void *)(unsigned long)infoArgs.metadata_ptr;
|
|
|
|
|
GraphicsResourceInfo->MetadataSizeInBytes = infoArgs.metadata_size;
|
2017-04-20 08:25:00 -04:00
|
|
|
GraphicsResourceInfo->Reserved = 0;
|
2016-03-05 01:12:40 -05:00
|
|
|
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
|
|
error_release_buffer:
|
|
|
|
|
freeArgs.handle = importArgs.handle;
|
|
|
|
|
kmtIoctl(kfd_fd, AMDKFD_IOC_FREE_MEMORY_OF_GPU, &freeArgs);
|
|
|
|
|
error_release_aperture:
|
|
|
|
|
aperture_release_area(aperture, mem, infoArgs.size);
|
|
|
|
|
error_free_metadata:
|
|
|
|
|
free(metadata);
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
HSAKMT_STATUS fmm_share_memory(void *MemoryAddress,
|
2016-11-22 14:35:35 -05:00
|
|
|
HSAuint64 SizeInBytes,
|
|
|
|
|
HsaSharedMemoryHandle *SharedMemoryHandle)
|
|
|
|
|
{
|
|
|
|
|
int r = 0;
|
|
|
|
|
HSAuint32 gpu_id = 0;
|
|
|
|
|
vm_object_t *obj = NULL;
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture = NULL;
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_ipc_export_handle_args exportArgs = {0};
|
2016-11-22 14:35:35 -05:00
|
|
|
HsaApertureInfo ApeInfo;
|
|
|
|
|
HsaSharedMemoryStruct *SharedMemoryStruct =
|
|
|
|
|
to_hsa_shared_memory_struct(SharedMemoryHandle);
|
|
|
|
|
|
|
|
|
|
if (SizeInBytes >= (1ULL << ((sizeof(HSAuint32) * 8) + PAGE_SHIFT)))
|
|
|
|
|
return HSAKMT_STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
|
|
aperture = fmm_find_aperture(MemoryAddress, &ApeInfo);
|
|
|
|
|
if (!aperture)
|
|
|
|
|
return HSAKMT_STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
obj = vm_find_object_by_address(aperture, MemoryAddress, 0);
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
if (!obj)
|
|
|
|
|
return HSAKMT_STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
|
|
r = validate_nodeid(obj->node_id, &gpu_id);
|
2017-07-24 14:46:13 -04:00
|
|
|
if (r != HSAKMT_STATUS_SUCCESS)
|
|
|
|
|
return r;
|
2017-07-24 15:12:24 -04:00
|
|
|
if (!gpu_id && is_dgpu) {
|
2018-08-03 03:01:22 -04:00
|
|
|
/* Sharing non paged system memory. Use first GPU which was
|
2017-07-24 15:12:24 -04:00
|
|
|
* used during allocation. See fmm_allocate_host_gpu()
|
|
|
|
|
*/
|
2018-08-03 03:01:22 -04:00
|
|
|
if (!g_first_gpu_mem)
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
|
|
|
|
|
gpu_id = g_first_gpu_mem->gpu_id;
|
2017-07-24 15:12:24 -04:00
|
|
|
}
|
2016-11-22 14:35:35 -05:00
|
|
|
exportArgs.handle = obj->handle;
|
|
|
|
|
exportArgs.gpu_id = gpu_id;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r = kmtIoctl(kfd_fd, AMDKFD_IOC_IPC_EXPORT_HANDLE, (void *)&exportArgs);
|
|
|
|
|
if (r)
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
|
|
|
|
|
memcpy(SharedMemoryStruct->ShareHandle, exportArgs.share_handle,
|
|
|
|
|
sizeof(SharedMemoryStruct->ShareHandle));
|
|
|
|
|
SharedMemoryStruct->ApeInfo = ApeInfo;
|
|
|
|
|
SharedMemoryStruct->SizeInPages = (HSAuint32) (SizeInBytes >> PAGE_SHIFT);
|
|
|
|
|
SharedMemoryStruct->ExportGpuId = gpu_id;
|
|
|
|
|
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HSAKMT_STATUS fmm_register_shared_memory(const HsaSharedMemoryHandle *SharedMemoryHandle,
|
|
|
|
|
HSAuint64 *SizeInBytes,
|
|
|
|
|
void **MemoryAddress,
|
|
|
|
|
uint32_t *gpu_id_array,
|
|
|
|
|
uint32_t gpu_id_array_size)
|
|
|
|
|
{
|
|
|
|
|
int r = 0;
|
|
|
|
|
HSAKMT_STATUS err = HSAKMT_STATUS_ERROR;
|
|
|
|
|
vm_object_t *obj = NULL;
|
|
|
|
|
void *reservedMem = NULL;
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2018-01-25 13:47:14 -08:00
|
|
|
struct kfd_ioctl_ipc_import_handle_args importArgs = {0};
|
|
|
|
|
struct kfd_ioctl_free_memory_of_gpu_args freeArgs = {0};
|
2016-11-22 14:35:35 -05:00
|
|
|
const HsaSharedMemoryStruct *SharedMemoryStruct =
|
|
|
|
|
to_const_hsa_shared_memory_struct(SharedMemoryHandle);
|
|
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
if (gpu_id_array_size > 0 && !gpu_id_array)
|
2016-11-22 14:35:35 -05:00
|
|
|
return HSAKMT_STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
|
|
memcpy(importArgs.share_handle, SharedMemoryStruct->ShareHandle,
|
|
|
|
|
sizeof(importArgs.share_handle));
|
|
|
|
|
importArgs.gpu_id = SharedMemoryStruct->ExportGpuId;
|
|
|
|
|
|
|
|
|
|
aperture = fmm_get_aperture(SharedMemoryStruct->ApeInfo);
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
reservedMem = aperture_allocate_area(aperture,
|
2018-08-04 15:58:23 -04:00
|
|
|
(SharedMemoryStruct->SizeInPages << PAGE_SHIFT));
|
2016-11-22 14:35:35 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
if (!reservedMem) {
|
|
|
|
|
err = HSAKMT_STATUS_NO_MEMORY;
|
|
|
|
|
goto err_free_buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
importArgs.va_addr = (uint64_t)reservedMem;
|
|
|
|
|
r = kmtIoctl(kfd_fd, AMDKFD_IOC_IPC_IMPORT_HANDLE, (void *)&importArgs);
|
|
|
|
|
if (r) {
|
|
|
|
|
err = HSAKMT_STATUS_ERROR;
|
|
|
|
|
goto err_import;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
obj = aperture_allocate_object(aperture, reservedMem, importArgs.handle,
|
|
|
|
|
(SharedMemoryStruct->SizeInPages << PAGE_SHIFT),
|
|
|
|
|
0);
|
|
|
|
|
if (!obj) {
|
|
|
|
|
err = HSAKMT_STATUS_NO_MEMORY;
|
|
|
|
|
goto err_free_mem;
|
|
|
|
|
}
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
if (importArgs.mmap_offset) {
|
2018-03-01 17:31:38 -05:00
|
|
|
int32_t gpu_mem_id = gpu_mem_find_by_gpu_id(importArgs.gpu_id);
|
|
|
|
|
int map_fd;
|
|
|
|
|
void *ret;
|
|
|
|
|
|
|
|
|
|
if (gpu_mem_id < 0) {
|
|
|
|
|
err = HSAKMT_STATUS_ERROR;
|
|
|
|
|
goto err_free_obj;
|
|
|
|
|
}
|
|
|
|
|
map_fd = importArgs.mmap_offset >= (1ULL<<40) ? kfd_fd :
|
|
|
|
|
gpu_mem[gpu_mem_id].drm_render_fd;
|
|
|
|
|
ret = mmap(reservedMem, (SharedMemoryStruct->SizeInPages << PAGE_SHIFT),
|
|
|
|
|
PROT_READ | PROT_WRITE,
|
|
|
|
|
MAP_SHARED | MAP_FIXED, map_fd, importArgs.mmap_offset);
|
2016-11-22 14:35:35 -05:00
|
|
|
if (ret == MAP_FAILED) {
|
|
|
|
|
err = HSAKMT_STATUS_ERROR;
|
|
|
|
|
goto err_free_obj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*MemoryAddress = reservedMem;
|
|
|
|
|
*SizeInBytes = (SharedMemoryStruct->SizeInPages << PAGE_SHIFT);
|
|
|
|
|
|
|
|
|
|
if (gpu_id_array_size > 0) {
|
|
|
|
|
obj->registered_device_id_array = gpu_id_array;
|
|
|
|
|
obj->registered_device_id_array_size = gpu_id_array_size;
|
|
|
|
|
}
|
|
|
|
|
obj->is_imported_kfd_bo = true;
|
|
|
|
|
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
err_free_obj:
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
vm_remove_object(aperture, obj);
|
|
|
|
|
err_free_mem:
|
|
|
|
|
aperture_release_area(aperture, reservedMem, (SharedMemoryStruct->SizeInPages << PAGE_SHIFT));
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
err_free_buffer:
|
|
|
|
|
freeArgs.handle = importArgs.handle;
|
|
|
|
|
kmtIoctl(kfd_fd, AMDKFD_IOC_FREE_MEMORY_OF_GPU, &freeArgs);
|
|
|
|
|
err_import:
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
static HSAKMT_STATUS fmm_deregister_user_memory(void *addr)
|
2015-12-23 17:23:25 +02:00
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
vm_object_t *obj;
|
2015-12-23 17:23:25 +02:00
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2015-11-06 18:28:30 -05:00
|
|
|
|
|
|
|
|
/* Find the size and start address in SVM space */
|
2015-12-23 17:23:25 +02:00
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2016-11-09 14:54:17 -05:00
|
|
|
obj = vm_find_object_by_userptr(aperture, addr, 0);
|
2017-04-20 08:25:00 -04:00
|
|
|
if (!obj || obj->registration_count > 1) {
|
2015-11-06 18:28:30 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2016-11-09 14:54:17 -05:00
|
|
|
return HSAKMT_STATUS_ERROR;
|
2015-11-06 18:28:30 -05:00
|
|
|
}
|
2015-12-23 17:23:25 +02:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
/* Destroy BO */
|
2018-06-20 13:30:06 +08:00
|
|
|
__fmm_release(obj, aperture);
|
2015-11-06 18:28:30 -05:00
|
|
|
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HSAKMT_STATUS fmm_deregister_memory(void *address)
|
|
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture = NULL;
|
2015-11-06 18:28:30 -05:00
|
|
|
vm_object_t *object = NULL;
|
2017-04-20 08:25:00 -04:00
|
|
|
unsigned int i;
|
2016-11-09 14:54:17 -05:00
|
|
|
HSAuint32 page_offset = (HSAint64)address & (PAGE_SIZE - 1);
|
2015-11-06 18:28:30 -05:00
|
|
|
|
2018-08-10 17:05:42 -04:00
|
|
|
if ((address >= svm.dgpu_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_aperture->limit))
|
|
|
|
|
aperture = svm.dgpu_aperture;
|
|
|
|
|
else if ((address >= svm.dgpu_alt_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_alt_aperture->limit))
|
|
|
|
|
aperture = svm.dgpu_alt_aperture;
|
2016-03-05 01:12:40 -05:00
|
|
|
else
|
|
|
|
|
for (i = 0; i < gpu_mem_count; i++) {
|
|
|
|
|
if (gpu_mem[i].gpu_id != NON_VALID_GPU_ID &&
|
|
|
|
|
address >= gpu_mem[i].gpuvm_aperture.base &&
|
|
|
|
|
address <= gpu_mem[i].gpuvm_aperture.limit) {
|
|
|
|
|
aperture = &gpu_mem[i].gpuvm_aperture;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!aperture) {
|
|
|
|
|
/* If address isn't found in any aperture, we assume
|
|
|
|
|
* that this is system memory address. On APUs, there
|
|
|
|
|
* is nothing to do (for now).
|
|
|
|
|
*/
|
|
|
|
|
if (!is_dgpu)
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
/* If the userptr object had a
|
|
|
|
|
* registered_device_id_array, it will be freed by
|
2015-11-06 18:28:30 -05:00
|
|
|
* __fmm_release. Also the object will be
|
|
|
|
|
* removed. Therefore we can short-circuit the rest of
|
|
|
|
|
* the function below.
|
|
|
|
|
*/
|
|
|
|
|
return fmm_deregister_user_memory(address);
|
2015-12-23 17:23:25 +02:00
|
|
|
}
|
|
|
|
|
|
2015-11-06 18:28:30 -05:00
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
object = vm_find_object_by_address(aperture,
|
|
|
|
|
VOID_PTR_SUB(address, page_offset), 0);
|
2016-03-05 01:12:40 -05:00
|
|
|
if (!object) {
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2016-01-07 16:28:20 -05:00
|
|
|
return HSAKMT_STATUS_MEMORY_NOT_REGISTERED;
|
2016-03-05 01:12:40 -05:00
|
|
|
}
|
2015-12-23 17:23:25 +02:00
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
if (object->registration_count > 1) {
|
|
|
|
|
--object->registration_count;
|
2016-03-05 01:12:40 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2016-11-09 14:54:17 -05:00
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-22 14:35:35 -05:00
|
|
|
if (object->metadata || object->userptr || object->is_imported_kfd_bo) {
|
2016-03-05 01:12:40 -05:00
|
|
|
/* An object with metadata is an imported graphics
|
2016-11-09 14:54:17 -05:00
|
|
|
* buffer. Deregistering imported graphics buffers or
|
|
|
|
|
* userptrs means releasing the BO.
|
|
|
|
|
*/
|
2016-03-05 01:12:40 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2018-06-20 13:30:06 +08:00
|
|
|
__fmm_release(object, aperture);
|
2016-03-05 01:12:40 -05:00
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-30 10:56:38 -05:00
|
|
|
if (!object->registered_device_id_array ||
|
|
|
|
|
object->registered_device_id_array_size <= 0) {
|
2016-03-05 01:12:40 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return HSAKMT_STATUS_MEMORY_NOT_REGISTERED;
|
|
|
|
|
}
|
2015-11-06 18:28:30 -05:00
|
|
|
|
2017-11-30 10:56:38 -05:00
|
|
|
if (object->registered_device_id_array) {
|
|
|
|
|
free(object->registered_device_id_array);
|
|
|
|
|
object->registered_device_id_array = NULL;
|
|
|
|
|
object->registered_device_id_array_size = 0;
|
|
|
|
|
}
|
2016-09-01 23:25:42 -04:00
|
|
|
if (object->registered_node_id_array)
|
|
|
|
|
free(object->registered_node_id_array);
|
|
|
|
|
object->registered_node_id_array = NULL;
|
2016-11-09 14:54:17 -05:00
|
|
|
object->registration_count = 0;
|
2015-12-23 17:23:25 +02:00
|
|
|
|
2016-03-05 01:12:40 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
2016-01-07 16:28:20 -05:00
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
2015-12-23 17:23:25 +02:00
|
|
|
}
|
2016-02-24 17:30:48 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function unmaps all nodes on current mapped nodes list that are not included on nodes_to_map
|
|
|
|
|
* and maps nodes_to_map
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
HSAKMT_STATUS fmm_map_to_gpu_nodes(void *address, uint64_t size,
|
2017-08-15 17:13:55 -04:00
|
|
|
uint32_t *nodes_to_map, uint64_t num_of_nodes,
|
2016-02-24 17:30:48 +02:00
|
|
|
uint64_t *gpuvm_address)
|
|
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2016-02-24 17:30:48 +02:00
|
|
|
vm_object_t *object = NULL;
|
2017-11-30 10:56:38 -05:00
|
|
|
uint32_t i;
|
|
|
|
|
bool userptr = false;
|
2016-02-24 17:30:48 +02:00
|
|
|
uint32_t *registered_node_id_array, registered_node_id_array_size;
|
|
|
|
|
HSAKMT_STATUS ret = HSAKMT_STATUS_ERROR;
|
|
|
|
|
int retcode = 0;
|
|
|
|
|
|
2017-08-15 17:13:55 -04:00
|
|
|
if (!num_of_nodes || !nodes_to_map || !address)
|
2016-02-24 17:30:48 +02:00
|
|
|
return HSAKMT_STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
|
|
/* Find object by address */
|
2018-08-10 17:05:42 -04:00
|
|
|
if ((address >= svm.dgpu_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_aperture->limit))
|
|
|
|
|
aperture = svm.dgpu_aperture;
|
|
|
|
|
else if ((address >= svm.dgpu_alt_aperture->base) &&
|
|
|
|
|
(address <= svm.dgpu_alt_aperture->limit))
|
|
|
|
|
aperture = svm.dgpu_alt_aperture;
|
2016-02-24 17:30:48 +02:00
|
|
|
else {
|
2018-08-10 17:05:42 -04:00
|
|
|
aperture = svm.dgpu_aperture;
|
2016-02-24 17:30:48 +02:00
|
|
|
userptr = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
|
|
|
|
if (userptr && is_dgpu)
|
2016-11-09 14:54:17 -05:00
|
|
|
object = vm_find_object_by_userptr(aperture, address, size);
|
2016-02-24 17:30:48 +02:00
|
|
|
else
|
2016-09-13 12:44:29 -04:00
|
|
|
object = vm_find_object_by_address(aperture, address, 0);
|
2016-02-24 17:30:48 +02:00
|
|
|
|
|
|
|
|
if (!object) {
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-09 14:54:17 -05:00
|
|
|
/* For userptr, we ignore the nodes array and map all registered nodes.
|
|
|
|
|
* This is to simply the implementation of allowing the same memory
|
|
|
|
|
* region to be registered multiple times.
|
|
|
|
|
*/
|
|
|
|
|
if (userptr && is_dgpu) {
|
|
|
|
|
retcode = _fmm_map_to_gpu_userptr(address, size,
|
|
|
|
|
gpuvm_address, object);
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return retcode;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-24 17:30:48 +02:00
|
|
|
/* Verify that all nodes to map are registered already */
|
|
|
|
|
registered_node_id_array = all_gpu_id_array;
|
|
|
|
|
registered_node_id_array_size = all_gpu_id_array_size;
|
|
|
|
|
if (object->registered_device_id_array_size > 0 &&
|
2017-04-20 08:25:00 -04:00
|
|
|
object->registered_device_id_array) {
|
2016-02-24 17:30:48 +02:00
|
|
|
registered_node_id_array = object->registered_device_id_array;
|
|
|
|
|
registered_node_id_array_size = object->registered_device_id_array_size;
|
|
|
|
|
}
|
2017-08-15 17:13:55 -04:00
|
|
|
for (i = 0 ; i < num_of_nodes; i++) {
|
2017-11-30 10:56:38 -05:00
|
|
|
if (!id_in_array(nodes_to_map[i], registered_node_id_array,
|
|
|
|
|
registered_node_id_array_size)) {
|
2016-02-24 17:30:48 +02:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Unmap buffer from all nodes that have this buffer mapped that are not included on nodes_to_map array */
|
|
|
|
|
if (object->mapped_device_id_array_size > 0) {
|
2017-08-21 19:58:35 -04:00
|
|
|
uint32_t temp_node_id_array[object->mapped_device_id_array_size];
|
|
|
|
|
uint32_t temp_node_id_array_size = 0;
|
|
|
|
|
|
2016-02-24 17:30:48 +02:00
|
|
|
for (i = 0 ; i < object->mapped_device_id_array_size / sizeof(uint32_t); i++) {
|
2017-11-30 10:56:38 -05:00
|
|
|
if (!id_in_array(object->mapped_device_id_array[i],
|
|
|
|
|
nodes_to_map,
|
|
|
|
|
num_of_nodes*sizeof(uint32_t)))
|
|
|
|
|
temp_node_id_array[temp_node_id_array_size++] =
|
|
|
|
|
object->mapped_device_id_array[i];
|
2016-02-24 17:30:48 +02:00
|
|
|
}
|
|
|
|
|
temp_node_id_array_size *= sizeof(uint32_t);
|
|
|
|
|
|
2017-11-20 10:57:37 -05:00
|
|
|
if (temp_node_id_array_size) {
|
|
|
|
|
ret = _fmm_unmap_from_gpu(aperture, address,
|
|
|
|
|
temp_node_id_array,
|
|
|
|
|
temp_node_id_array_size,
|
|
|
|
|
object);
|
|
|
|
|
if (ret != HSAKMT_STATUS_SUCCESS) {
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-24 17:30:48 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-30 10:56:38 -05:00
|
|
|
/* Remove already mapped nodes from nodes_to_map
|
|
|
|
|
* to generate the final map list
|
|
|
|
|
*/
|
|
|
|
|
uint32_t map_node_id_array[num_of_nodes];
|
|
|
|
|
uint32_t map_node_id_array_size = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_of_nodes; i++) {
|
|
|
|
|
if (!id_in_array(nodes_to_map[i],
|
|
|
|
|
object->mapped_device_id_array,
|
|
|
|
|
object->mapped_device_id_array_size))
|
|
|
|
|
map_node_id_array[map_node_id_array_size++] =
|
|
|
|
|
nodes_to_map[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (map_node_id_array_size)
|
2017-11-30 11:06:45 -05:00
|
|
|
retcode = _fmm_map_to_gpu(aperture, address, size, object,
|
2017-11-30 10:56:38 -05:00
|
|
|
map_node_id_array,
|
|
|
|
|
map_node_id_array_size * sizeof(uint32_t));
|
2016-02-24 17:30:48 +02:00
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
|
|
|
|
|
|
|
|
|
if (retcode != 0)
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-09-01 23:25:42 -04:00
|
|
|
|
|
|
|
|
HSAKMT_STATUS fmm_get_mem_info(const void *address, HsaPointerInfo *info)
|
|
|
|
|
{
|
|
|
|
|
HSAKMT_STATUS ret = HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
uint32_t i;
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2016-09-01 23:25:42 -04:00
|
|
|
vm_object_t *vm_obj;
|
|
|
|
|
|
|
|
|
|
memset(info, 0, sizeof(HsaPointerInfo));
|
|
|
|
|
|
2016-11-22 14:35:35 -05:00
|
|
|
aperture = fmm_find_aperture(address, NULL);
|
2016-09-01 23:25:42 -04:00
|
|
|
|
2017-11-20 16:15:29 -05:00
|
|
|
pthread_mutex_lock(&aperture->fmm_mutex);
|
2016-09-13 12:44:29 -04:00
|
|
|
vm_obj = vm_find_object_by_address_range(aperture, address);
|
2016-09-01 23:25:42 -04:00
|
|
|
if (!vm_obj)
|
2016-09-13 12:44:29 -04:00
|
|
|
vm_obj = vm_find_object_by_userptr_range(aperture, address);
|
2016-09-01 23:25:42 -04:00
|
|
|
|
|
|
|
|
if (!vm_obj) {
|
|
|
|
|
info->Type = HSA_POINTER_UNKNOWN;
|
|
|
|
|
ret = HSAKMT_STATUS_ERROR;
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm_obj->metadata)
|
|
|
|
|
info->Type = HSA_POINTER_REGISTERED_GRAPHICS;
|
|
|
|
|
else if (vm_obj->userptr)
|
|
|
|
|
info->Type = HSA_POINTER_REGISTERED_USER;
|
|
|
|
|
else
|
|
|
|
|
info->Type = HSA_POINTER_ALLOCATED;
|
|
|
|
|
|
|
|
|
|
info->Node = vm_obj->node_id;
|
|
|
|
|
info->GPUAddress = (HSAuint64)vm_obj->start;
|
|
|
|
|
info->SizeInBytes = vm_obj->size;
|
|
|
|
|
/* registered nodes */
|
|
|
|
|
info->NRegisteredNodes =
|
|
|
|
|
vm_obj->registered_device_id_array_size / sizeof(uint32_t);
|
|
|
|
|
if (info->NRegisteredNodes && !vm_obj->registered_node_id_array) {
|
|
|
|
|
vm_obj->registered_node_id_array = (uint32_t *)
|
|
|
|
|
(uint32_t *)malloc(vm_obj->registered_device_id_array_size);
|
|
|
|
|
/* vm_obj->registered_node_id_array allocated here will be
|
2017-11-20 16:15:29 -05:00
|
|
|
* freed whenever the registration is changed (deregistration or
|
|
|
|
|
* register to new nodes) or the memory being freed
|
2016-09-01 23:25:42 -04:00
|
|
|
*/
|
2017-04-20 08:25:00 -04:00
|
|
|
for (i = 0; i < info->NRegisteredNodes; i++)
|
2016-09-01 23:25:42 -04:00
|
|
|
gpuid_to_nodeid(vm_obj->registered_device_id_array[i],
|
|
|
|
|
&vm_obj->registered_node_id_array[i]);
|
|
|
|
|
}
|
|
|
|
|
info->RegisteredNodes = vm_obj->registered_node_id_array;
|
|
|
|
|
/* mapped nodes */
|
|
|
|
|
info->NMappedNodes =
|
|
|
|
|
vm_obj->mapped_device_id_array_size / sizeof(uint32_t);
|
|
|
|
|
if (info->NMappedNodes && !vm_obj->mapped_node_id_array) {
|
|
|
|
|
vm_obj->mapped_node_id_array =
|
|
|
|
|
(uint32_t *)malloc(vm_obj->mapped_device_id_array_size);
|
|
|
|
|
/* vm_obj->mapped_node_id_array allocated here will be
|
2017-11-20 16:15:29 -05:00
|
|
|
* freed whenever the mapping is changed (unmapped or map
|
|
|
|
|
* to new nodes) or memory being freed
|
2016-09-01 23:25:42 -04:00
|
|
|
*/
|
2017-04-20 08:25:00 -04:00
|
|
|
for (i = 0; i < info->NMappedNodes; i++)
|
2016-09-01 23:25:42 -04:00
|
|
|
gpuid_to_nodeid(vm_obj->mapped_device_id_array[i],
|
|
|
|
|
&vm_obj->mapped_node_id_array[i]);
|
|
|
|
|
}
|
|
|
|
|
info->MappedNodes = vm_obj->mapped_node_id_array;
|
|
|
|
|
info->UserData = vm_obj->user_data;
|
|
|
|
|
|
|
|
|
|
if (info->Type == HSA_POINTER_REGISTERED_USER) {
|
|
|
|
|
info->CPUAddress = vm_obj->userptr;
|
|
|
|
|
info->SizeInBytes = vm_obj->userptr_size;
|
2017-04-20 08:25:00 -04:00
|
|
|
info->GPUAddress += ((HSAuint64)info->CPUAddress & (PAGE_SIZE - 1));
|
|
|
|
|
} else if (info->Type == HSA_POINTER_ALLOCATED) {
|
2016-09-01 23:25:42 -04:00
|
|
|
info->MemFlags.Value = vm_obj->flags;
|
|
|
|
|
info->CPUAddress = vm_obj->start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exit:
|
2017-11-20 16:15:29 -05:00
|
|
|
pthread_mutex_unlock(&aperture->fmm_mutex);
|
2016-09-01 23:25:42 -04:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HSAKMT_STATUS fmm_set_mem_user_data(const void *mem, void *usr_data)
|
|
|
|
|
{
|
2017-04-20 08:25:00 -04:00
|
|
|
manageable_aperture_t *aperture;
|
2016-09-01 23:25:42 -04:00
|
|
|
vm_object_t *vm_obj;
|
|
|
|
|
|
2016-11-22 14:35:35 -05:00
|
|
|
aperture = fmm_find_aperture(mem, NULL);
|
2016-09-01 23:25:42 -04:00
|
|
|
|
2016-09-13 12:44:29 -04:00
|
|
|
vm_obj = vm_find_object_by_address(aperture, mem, 0);
|
2016-09-01 23:25:42 -04:00
|
|
|
if (!vm_obj)
|
2016-11-09 14:54:17 -05:00
|
|
|
vm_obj = vm_find_object_by_userptr(aperture, mem, 0);
|
2016-09-01 23:25:42 -04:00
|
|
|
if (!vm_obj)
|
|
|
|
|
return HSAKMT_STATUS_ERROR;
|
|
|
|
|
|
|
|
|
|
vm_obj->user_data = usr_data;
|
|
|
|
|
return HSAKMT_STATUS_SUCCESS;
|
|
|
|
|
}
|
2017-01-10 14:34:47 -05:00
|
|
|
|
2017-04-20 08:25:00 -04:00
|
|
|
static void fmm_clear_aperture(manageable_aperture_t *app)
|
2017-01-10 14:34:47 -05:00
|
|
|
{
|
2018-06-28 18:24:54 +08:00
|
|
|
rbtree_node_t *n;
|
|
|
|
|
|
|
|
|
|
while ((n = rbtree_node_any(&app->tree, MID)))
|
|
|
|
|
vm_remove_object(app, vm_object_entry(n, 0));
|
2017-01-10 14:34:47 -05:00
|
|
|
|
|
|
|
|
while (app->vm_ranges)
|
|
|
|
|
vm_remove_area(app, app->vm_ranges);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is a special funcion that should be called only from the child process
|
|
|
|
|
* after a fork(). This will clear all vm_objects and mmaps duplicated from
|
|
|
|
|
* the parent.
|
|
|
|
|
*/
|
|
|
|
|
void fmm_clear_all_mem(void)
|
|
|
|
|
{
|
|
|
|
|
uint32_t i;
|
|
|
|
|
void *map_addr;
|
|
|
|
|
|
2018-03-01 17:31:38 -05:00
|
|
|
/* Close render node FDs. The child process needs to open new ones */
|
|
|
|
|
for (i = 0; i <= DRM_LAST_RENDER_NODE - DRM_FIRST_RENDER_NODE; i++)
|
|
|
|
|
if (drm_render_fds[i]) {
|
|
|
|
|
close(drm_render_fds[i]);
|
|
|
|
|
drm_render_fds[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-10 14:34:47 -05:00
|
|
|
/* Nothing is initialized. */
|
|
|
|
|
if (!gpu_mem)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
fmm_clear_aperture(&cpuvm_aperture);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < gpu_mem_count; i++) {
|
|
|
|
|
fmm_clear_aperture(&gpu_mem[i].gpuvm_aperture);
|
|
|
|
|
fmm_clear_aperture(&gpu_mem[i].scratch_physical);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-24 23:02:48 -05:00
|
|
|
if (dgpu_shared_aperture_limit) {
|
2018-08-10 17:05:42 -04:00
|
|
|
fmm_clear_aperture(&svm.apertures[SVM_DEFAULT]);
|
|
|
|
|
fmm_clear_aperture(&svm.apertures[SVM_COHERENT]);
|
2017-01-10 14:34:47 -05:00
|
|
|
|
|
|
|
|
/* Use the same dgpu range as the parent. If failed, then set
|
|
|
|
|
* is_dgpu_mem_init to false. Later on dgpu_mem_init will try
|
|
|
|
|
* to get a new range
|
|
|
|
|
*/
|
|
|
|
|
map_addr = mmap(dgpu_shared_aperture_base, (HSAuint64)(dgpu_shared_aperture_limit)-
|
|
|
|
|
(HSAuint64)(dgpu_shared_aperture_base) + 1, PROT_NONE,
|
|
|
|
|
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED, -1, 0);
|
|
|
|
|
|
|
|
|
|
if (map_addr == MAP_FAILED) {
|
|
|
|
|
munmap(dgpu_shared_aperture_base,
|
|
|
|
|
(HSAuint64)(dgpu_shared_aperture_limit) -
|
|
|
|
|
(HSAuint64)(dgpu_shared_aperture_base) + 1);
|
|
|
|
|
|
|
|
|
|
dgpu_shared_aperture_base = NULL;
|
|
|
|
|
dgpu_shared_aperture_limit = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (all_gpu_id_array)
|
|
|
|
|
free(all_gpu_id_array);
|
|
|
|
|
|
|
|
|
|
all_gpu_id_array_size = 0;
|
|
|
|
|
all_gpu_id_array = NULL;
|
|
|
|
|
|
|
|
|
|
gpu_mem_count = 0;
|
|
|
|
|
free(gpu_mem);
|
|
|
|
|
}
|