libhsakmt: Fix userptr mappings on gfx802

The memory size alignment workaround for a TLB bug on gfx802 was
breaking userptrs because it would attempt to get_user_pages beyond
the end of a VMA. Refine this workaround based on our understanding
of the HW bug. It only affects L2 cacheline allocation, which is
decided by the last page in the cache line (8 entries = 32KB of
address space). Thus aligning memory allocation so that the last
page falls on the end of a 8 entry TLB cache line allows caching
to work correctly.

Imported images require specific alignments. If their size is not
naturally aligned with 8 cache lines, it may have bad TLB cache
performance.

This patch will only have the desired effect if redundant size
padding in KFD is also removed.

Change-Id: I984cbe7fa61fec04d70fa387aaf9aab370eabeb9
Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Этот коммит содержится в:
Felix Kuehling
2019-08-30 00:14:26 -04:00
родитель ec1461b84b
Коммит e320913e9e
+26 -20
Просмотреть файл
@@ -413,8 +413,6 @@ static vm_object_t *vm_find_object_by_address_userptr(manageable_aperture_t *app
{
vm_object_t *cur = NULL;
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;
@@ -561,8 +559,7 @@ static bool aperture_is_valid(void *app_base, void *app_limit)
*/
static uint64_t vm_align_area_size(manageable_aperture_t *app, uint64_t size)
{
return ALIGN_UP(ALIGN_UP(size, app->align) + (uint64_t)app->guard_pages * PAGE_SIZE,
app->align);
return size + (uint64_t)app->guard_pages * PAGE_SIZE;
}
/*
@@ -632,6 +629,7 @@ static void *reserved_aperture_allocate_aligned(manageable_aperture_t *app,
uint64_t MemorySizeInBytes,
uint64_t align)
{
uint64_t offset = 0, orig_align = align;
vm_area_t *cur, *next;
void *start;
@@ -644,12 +642,22 @@ static void *reserved_aperture_allocate_aligned(manageable_aperture_t *app,
while (align < GPU_HUGE_PAGE_SIZE && MemorySizeInBytes >= (align << 1))
align <<= 1;
/* If no specific alignment was requested, align the end of
* buffers instead of the start. For fragment optimizations,
* aligning the start or the end achieves the same effective
* optimization. End alignment to the TLB cache line size is
* needed as a workaround for TLB issues on some older GPUs.
*/
if (orig_align <= (uint64_t)PAGE_SIZE)
offset = align - (MemorySizeInBytes & (align - 1));
MemorySizeInBytes = vm_align_area_size(app, MemorySizeInBytes);
/* Find a big enough "hole" in the address space */
cur = NULL;
next = app->vm_ranges;
start = address ? address : (void *)ALIGN_UP((uint64_t)app->base, align);
start = address ? address :
(void *)(ALIGN_UP((uint64_t)app->base, align) + offset);
while (next) {
if (next->start > start &&
VOID_PTRS_SUB(next->start, start) >= MemorySizeInBytes)
@@ -658,7 +666,7 @@ static void *reserved_aperture_allocate_aligned(manageable_aperture_t *app,
cur = next;
next = next->next;
if (!address)
start = (void *)ALIGN_UP((uint64_t)cur->end + 1, align);
start = (void *)(ALIGN_UP((uint64_t)cur->end + 1, align) + offset);
}
if (!next && VOID_PTRS_SUB(app->limit, start) + 1 < MemorySizeInBytes)
/* No hole found and not enough space after the last area */
@@ -706,18 +714,12 @@ static void *mmap_aperture_allocate_aligned(manageable_aperture_t *aper,
return NULL;
}
if (align < aper->align)
align = aper->align;
/* 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 && size >= (align << 1))
align <<= 1;
/* Align memory size to match aperture requirements */
size = ALIGN_UP(size, aper->align);
/* Add padding to guarantee proper alignment and leave guard
* pages on both sides
*/
@@ -763,9 +765,6 @@ static void mmap_aperture_release(manageable_aperture_t *aper,
return;
}
/* Align memory size to match aperture requirements */
size = ALIGN_UP(size, aper->align);
/* Reset NUMA policy */
mbind(addr, size, MPOL_DEFAULT, NULL, 0, 0);
@@ -801,8 +800,6 @@ static vm_object_t *aperture_allocate_object(manageable_aperture_t *app,
{
vm_object_t *new_object;
MemorySizeInBytes = ALIGN_UP(MemorySizeInBytes, app->align);
/* Allocate new object */
new_object = vm_create_and_init_object(new_address,
MemorySizeInBytes,
@@ -929,7 +926,7 @@ static vm_object_t *fmm_allocate_memory_object(uint32_t gpu_id, void *mem,
/* Allocate memory from amdkfd */
args.gpu_id = gpu_id;
args.size = ALIGN_UP(MemorySizeInBytes, aperture->align);
args.size = MemorySizeInBytes;
args.flags = flags |
KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE;
@@ -1579,7 +1576,7 @@ static void *fmm_allocate_host_gpu(uint32_t node_id, void *address,
}
if (flags.ui32.AQLQueueMemory) {
uint64_t my_buf_size = ALIGN_UP(size, aperture->align) / 2;
uint64_t my_buf_size = size / 2;
memset(ret, 0, MemorySizeInBytes);
mmap(VOID_PTR_ADD(mem, my_buf_size), MemorySizeInBytes,
@@ -1796,6 +1793,15 @@ static HSAKMT_STATUS init_mmap_apertures(HSAuint64 base, HSAuint64 limit,
{
void *addr;
if (align > (HSAuint32)PAGE_SIZE) {
/* This should never happen. Alignment constraints
* only apply to old GPUs that don't support 48-bit
* virtual addresses.
*/
pr_info("Falling back to reserved SVM apertures due to alignment contraints.\n");
return HSAKMT_STATUS_ERROR;
}
/* Set up one SVM aperture */
svm.apertures[SVM_DEFAULT].base = (void *)base;
svm.apertures[SVM_DEFAULT].limit = (void *)limit;
@@ -3080,7 +3086,7 @@ HSAKMT_STATUS fmm_register_graphics_handle(HSAuint64 GraphicsResourceHandle,
goto error_free_metadata;
pthread_mutex_lock(&aperture->fmm_mutex);
mem = aperture_allocate_area_aligned(aperture, NULL, infoArgs.size,
MAX(aperture->align, IMAGE_ALIGN));
IMAGE_ALIGN);
pthread_mutex_unlock(&aperture->fmm_mutex);
if (!mem)
goto error_free_metadata;