mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-16 09:48:16 +02:00
This breaks add_mapping() into three pieces:
1. get_aux_entry() adds AUX-TT pages as needed and returns the
L1 entry index, L1 entry address, and L1 entry map.
2. gen_aux_map_format_bits_for_isl_surf() computes the format-
specific information that goes in the AUX-TT entry.
3. add_mapping() is a lot dumber function that now just adds the
requested mapping with the requested format bits.
This lets us break out some additional helpers in the API which we want
to use for more direct AUX-TT management in ANV.
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3519>
624 lines
20 KiB
C
624 lines
20 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*/
|
|
|
|
/**
|
|
* The aux map provides a multi-level lookup of the main surface address which
|
|
* ends up providing information about the auxiliary surface data, including
|
|
* the address where the auxiliary data resides.
|
|
*
|
|
* The 48-bit VMA (GPU) address of the main surface is split to do the address
|
|
* lookup:
|
|
*
|
|
* 48 bit address of main surface
|
|
* +--------+--------+--------+------+
|
|
* | 47:36 | 35:24 | 23:16 | 15:0 |
|
|
* | L3-idx | L2-idx | L1-idx | ... |
|
|
* +--------+--------+--------+------+
|
|
*
|
|
* The GFX_AUX_TABLE_BASE_ADDR points to a buffer. The L3 Table Entry is
|
|
* located by indexing into this buffer as a uint64_t array using the L3-idx
|
|
* value. The 64-bit L3 entry is defined as:
|
|
*
|
|
* +-------+-------------+------+---+
|
|
* | 63:48 | 47:15 | 14:1 | 0 |
|
|
* | ... | L2-tbl-addr | ... | V |
|
|
* +-------+-------------+------+---+
|
|
*
|
|
* If the `V` (valid) bit is set, then the L2-tbl-addr gives the address for
|
|
* the level-2 table entries, with the lower address bits filled with zero.
|
|
* The L2 Table Entry is located by indexing into this buffer as a uint64_t
|
|
* array using the L2-idx value. The 64-bit L2 entry is similar to the L3
|
|
* entry, except with 2 additional address bits:
|
|
*
|
|
* +-------+-------------+------+---+
|
|
* | 63:48 | 47:13 | 12:1 | 0 |
|
|
* | ... | L1-tbl-addr | ... | V |
|
|
* +-------+-------------+------+---+
|
|
*
|
|
* If the `V` bit is set, then the L1-tbl-addr gives the address for the
|
|
* level-1 table entries, with the lower address bits filled with zero. The L1
|
|
* Table Entry is located by indexing into this buffer as a uint64_t array
|
|
* using the L1-idx value. The 64-bit L1 entry is defined as:
|
|
*
|
|
* +--------+------+-------+-------+-------+---------------+-----+---+
|
|
* | 63:58 | 57 | 56:54 | 53:52 | 51:48 | 47:8 | 7:1 | 0 |
|
|
* | Format | Y/Cr | Depth | TM | ... | aux-data-addr | ... | V |
|
|
* +--------+------+-------+-------+-------+---------------+-----+---+
|
|
*
|
|
* Where:
|
|
* - Format: See `get_format_encoding`
|
|
* - Y/Cr: 0=not-Y/Cr, 1=Y/Cr
|
|
* - (bit) Depth: See `get_bpp_encoding`
|
|
* - TM (Tile-mode): 0=Ys, 1=Y, 2=rsvd, 3=rsvd
|
|
* - aux-data-addr: VMA/GPU address for the aux-data
|
|
* - V: entry is valid
|
|
*/
|
|
|
|
#include "gen_aux_map.h"
|
|
#include "gen_gem.h"
|
|
|
|
#include "dev/gen_device_info.h"
|
|
|
|
#include "drm-uapi/i915_drm.h"
|
|
#include "util/list.h"
|
|
#include "util/ralloc.h"
|
|
#include "util/u_atomic.h"
|
|
#include "main/macros.h"
|
|
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <pthread.h>
|
|
|
|
static const bool aux_map_debug = false;
|
|
|
|
struct aux_map_buffer {
|
|
struct list_head link;
|
|
struct gen_buffer *buffer;
|
|
};
|
|
|
|
struct gen_aux_map_context {
|
|
void *driver_ctx;
|
|
pthread_mutex_t mutex;
|
|
struct gen_mapped_pinned_buffer_alloc *buffer_alloc;
|
|
uint32_t num_buffers;
|
|
struct list_head buffers;
|
|
uint64_t level3_base_addr;
|
|
uint64_t *level3_map;
|
|
uint32_t tail_offset, tail_remaining;
|
|
uint32_t state_num;
|
|
};
|
|
|
|
static bool
|
|
add_buffer(struct gen_aux_map_context *ctx)
|
|
{
|
|
struct aux_map_buffer *buf = ralloc(ctx, struct aux_map_buffer);
|
|
if (!buf)
|
|
return false;
|
|
|
|
const uint32_t size = 0x100000;
|
|
buf->buffer = ctx->buffer_alloc->alloc(ctx->driver_ctx, size);
|
|
if (!buf->buffer) {
|
|
ralloc_free(buf);
|
|
return false;
|
|
}
|
|
|
|
assert(buf->buffer->map != NULL);
|
|
|
|
list_addtail(&buf->link, &ctx->buffers);
|
|
ctx->tail_offset = 0;
|
|
ctx->tail_remaining = size;
|
|
p_atomic_inc(&ctx->num_buffers);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
advance_current_pos(struct gen_aux_map_context *ctx, uint32_t size)
|
|
{
|
|
assert(ctx->tail_remaining >= size);
|
|
ctx->tail_remaining -= size;
|
|
ctx->tail_offset += size;
|
|
}
|
|
|
|
static bool
|
|
align_and_verify_space(struct gen_aux_map_context *ctx, uint32_t size,
|
|
uint32_t align)
|
|
{
|
|
if (ctx->tail_remaining < size)
|
|
return false;
|
|
|
|
struct aux_map_buffer *tail =
|
|
list_last_entry(&ctx->buffers, struct aux_map_buffer, link);
|
|
uint64_t gpu = tail->buffer->gpu + ctx->tail_offset;
|
|
uint64_t aligned = align64(gpu, align);
|
|
|
|
if ((aligned - gpu) + size > ctx->tail_remaining) {
|
|
return false;
|
|
} else {
|
|
if (aligned - gpu > 0)
|
|
advance_current_pos(ctx, aligned - gpu);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static void
|
|
get_current_pos(struct gen_aux_map_context *ctx, uint64_t *gpu, uint64_t **map)
|
|
{
|
|
assert(!list_is_empty(&ctx->buffers));
|
|
struct aux_map_buffer *tail =
|
|
list_last_entry(&ctx->buffers, struct aux_map_buffer, link);
|
|
if (gpu)
|
|
*gpu = tail->buffer->gpu + ctx->tail_offset;
|
|
if (map)
|
|
*map = (uint64_t*)((uint8_t*)tail->buffer->map + ctx->tail_offset);
|
|
}
|
|
|
|
static bool
|
|
add_sub_table(struct gen_aux_map_context *ctx, uint32_t size,
|
|
uint32_t align, uint64_t *gpu, uint64_t **map)
|
|
{
|
|
if (!align_and_verify_space(ctx, size, align)) {
|
|
if (!add_buffer(ctx))
|
|
return false;
|
|
UNUSED bool aligned = align_and_verify_space(ctx, size, align);
|
|
assert(aligned);
|
|
}
|
|
get_current_pos(ctx, gpu, map);
|
|
memset(*map, 0, size);
|
|
advance_current_pos(ctx, size);
|
|
return true;
|
|
}
|
|
|
|
uint32_t
|
|
gen_aux_map_get_state_num(struct gen_aux_map_context *ctx)
|
|
{
|
|
return p_atomic_read(&ctx->state_num);
|
|
}
|
|
|
|
struct gen_aux_map_context *
|
|
gen_aux_map_init(void *driver_ctx,
|
|
struct gen_mapped_pinned_buffer_alloc *buffer_alloc,
|
|
const struct gen_device_info *devinfo)
|
|
{
|
|
struct gen_aux_map_context *ctx;
|
|
if (devinfo->gen < 12)
|
|
return NULL;
|
|
|
|
ctx = ralloc(NULL, struct gen_aux_map_context);
|
|
if (!ctx)
|
|
return NULL;
|
|
|
|
if (pthread_mutex_init(&ctx->mutex, NULL))
|
|
return NULL;
|
|
|
|
ctx->driver_ctx = driver_ctx;
|
|
ctx->buffer_alloc = buffer_alloc;
|
|
ctx->num_buffers = 0;
|
|
list_inithead(&ctx->buffers);
|
|
ctx->tail_offset = 0;
|
|
ctx->tail_remaining = 0;
|
|
ctx->state_num = 0;
|
|
|
|
if (add_sub_table(ctx, 32 * 1024, 32 * 1024, &ctx->level3_base_addr,
|
|
&ctx->level3_map)) {
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP L3: 0x%"PRIx64", map=%p\n",
|
|
ctx->level3_base_addr, ctx->level3_map);
|
|
p_atomic_inc(&ctx->state_num);
|
|
return ctx;
|
|
} else {
|
|
ralloc_free(ctx);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
gen_aux_map_finish(struct gen_aux_map_context *ctx)
|
|
{
|
|
if (!ctx)
|
|
return;
|
|
|
|
pthread_mutex_destroy(&ctx->mutex);
|
|
list_for_each_entry_safe(struct aux_map_buffer, buf, &ctx->buffers, link) {
|
|
ctx->buffer_alloc->free(ctx->driver_ctx, buf->buffer);
|
|
list_del(&buf->link);
|
|
p_atomic_dec(&ctx->num_buffers);
|
|
ralloc_free(buf);
|
|
}
|
|
|
|
ralloc_free(ctx);
|
|
}
|
|
|
|
uint64_t
|
|
gen_aux_map_get_base(struct gen_aux_map_context *ctx)
|
|
{
|
|
/**
|
|
* This get initialized in gen_aux_map_init, and never changes, so there is
|
|
* no need to lock the mutex.
|
|
*/
|
|
return ctx->level3_base_addr;
|
|
}
|
|
|
|
static struct aux_map_buffer *
|
|
find_buffer(struct gen_aux_map_context *ctx, uint64_t addr)
|
|
{
|
|
list_for_each_entry(struct aux_map_buffer, buf, &ctx->buffers, link) {
|
|
if (buf->buffer->gpu <= addr && buf->buffer->gpu_end > addr) {
|
|
return buf;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static uint64_t *
|
|
get_u64_entry_ptr(struct gen_aux_map_context *ctx, uint64_t addr)
|
|
{
|
|
struct aux_map_buffer *buf = find_buffer(ctx, addr);
|
|
assert(buf);
|
|
uintptr_t map_offset = addr - buf->buffer->gpu;
|
|
return (uint64_t*)((uint8_t*)buf->buffer->map + map_offset);
|
|
}
|
|
|
|
static uint8_t
|
|
get_format_encoding(const struct isl_surf *isl_surf)
|
|
{
|
|
switch(isl_surf->format) {
|
|
case ISL_FORMAT_R32G32B32A32_FLOAT: return 0x11;
|
|
case ISL_FORMAT_R32G32B32X32_FLOAT: return 0x11;
|
|
case ISL_FORMAT_R32G32B32A32_SINT: return 0x12;
|
|
case ISL_FORMAT_R32G32B32A32_UINT: return 0x13;
|
|
case ISL_FORMAT_R16G16B16A16_UNORM: return 0x14;
|
|
case ISL_FORMAT_R16G16B16A16_SNORM: return 0x15;
|
|
case ISL_FORMAT_R16G16B16A16_SINT: return 0x16;
|
|
case ISL_FORMAT_R16G16B16A16_UINT: return 0x17;
|
|
case ISL_FORMAT_R16G16B16A16_FLOAT: return 0x10;
|
|
case ISL_FORMAT_R16G16B16X16_FLOAT: return 0x10;
|
|
case ISL_FORMAT_R32G32_FLOAT: return 0x11;
|
|
case ISL_FORMAT_R32G32_SINT: return 0x12;
|
|
case ISL_FORMAT_R32G32_UINT: return 0x13;
|
|
case ISL_FORMAT_B8G8R8A8_UNORM: return 0xA;
|
|
case ISL_FORMAT_B8G8R8X8_UNORM: return 0xA;
|
|
case ISL_FORMAT_B8G8R8A8_UNORM_SRGB: return 0xA;
|
|
case ISL_FORMAT_B8G8R8X8_UNORM_SRGB: return 0xA;
|
|
case ISL_FORMAT_R10G10B10A2_UNORM: return 0x18;
|
|
case ISL_FORMAT_R10G10B10A2_UNORM_SRGB: return 0x18;
|
|
case ISL_FORMAT_R10G10B10_FLOAT_A2_UNORM: return 0x19;
|
|
case ISL_FORMAT_R10G10B10A2_UINT: return 0x1A;
|
|
case ISL_FORMAT_R8G8B8A8_UNORM: return 0xA;
|
|
case ISL_FORMAT_R8G8B8A8_UNORM_SRGB: return 0xA;
|
|
case ISL_FORMAT_R8G8B8A8_SNORM: return 0x1B;
|
|
case ISL_FORMAT_R8G8B8A8_SINT: return 0x1C;
|
|
case ISL_FORMAT_R8G8B8A8_UINT: return 0x1D;
|
|
case ISL_FORMAT_R16G16_UNORM: return 0x14;
|
|
case ISL_FORMAT_R16G16_SNORM: return 0x15;
|
|
case ISL_FORMAT_R16G16_SINT: return 0x16;
|
|
case ISL_FORMAT_R16G16_UINT: return 0x17;
|
|
case ISL_FORMAT_R16G16_FLOAT: return 0x10;
|
|
case ISL_FORMAT_B10G10R10A2_UNORM: return 0x18;
|
|
case ISL_FORMAT_B10G10R10A2_UNORM_SRGB: return 0x18;
|
|
case ISL_FORMAT_R11G11B10_FLOAT: return 0x1E;
|
|
case ISL_FORMAT_R32_SINT: return 0x12;
|
|
case ISL_FORMAT_R32_UINT: return 0x13;
|
|
case ISL_FORMAT_R32_FLOAT: return 0x11;
|
|
case ISL_FORMAT_R24_UNORM_X8_TYPELESS: return 0x11;
|
|
case ISL_FORMAT_B5G6R5_UNORM: return 0xA;
|
|
case ISL_FORMAT_B5G6R5_UNORM_SRGB: return 0xA;
|
|
case ISL_FORMAT_B5G5R5A1_UNORM: return 0xA;
|
|
case ISL_FORMAT_B5G5R5A1_UNORM_SRGB: return 0xA;
|
|
case ISL_FORMAT_B4G4R4A4_UNORM: return 0xA;
|
|
case ISL_FORMAT_B4G4R4A4_UNORM_SRGB: return 0xA;
|
|
case ISL_FORMAT_R8G8_UNORM: return 0xA;
|
|
case ISL_FORMAT_R8G8_SNORM: return 0x1B;
|
|
case ISL_FORMAT_R8G8_SINT: return 0x1C;
|
|
case ISL_FORMAT_R8G8_UINT: return 0x1D;
|
|
case ISL_FORMAT_R16_UNORM: return 0x14;
|
|
case ISL_FORMAT_R16_SNORM: return 0x15;
|
|
case ISL_FORMAT_R16_SINT: return 0x16;
|
|
case ISL_FORMAT_R16_UINT: return 0x17;
|
|
case ISL_FORMAT_R16_FLOAT: return 0x10;
|
|
case ISL_FORMAT_B5G5R5X1_UNORM: return 0xA;
|
|
case ISL_FORMAT_B5G5R5X1_UNORM_SRGB: return 0xA;
|
|
case ISL_FORMAT_A1B5G5R5_UNORM: return 0xA;
|
|
case ISL_FORMAT_A4B4G4R4_UNORM: return 0xA;
|
|
case ISL_FORMAT_R8_UNORM: return 0xA;
|
|
case ISL_FORMAT_R8_SNORM: return 0x1B;
|
|
case ISL_FORMAT_R8_SINT: return 0x1C;
|
|
case ISL_FORMAT_R8_UINT: return 0x1D;
|
|
case ISL_FORMAT_A8_UNORM: return 0xA;
|
|
default:
|
|
unreachable("Unsupported aux-map format!");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static uint8_t
|
|
get_bpp_encoding(uint16_t bpp)
|
|
{
|
|
switch (bpp) {
|
|
case 16: return 0;
|
|
case 10: return 1;
|
|
case 12: return 2;
|
|
case 8: return 4;
|
|
case 32: return 5;
|
|
case 64: return 6;
|
|
case 128: return 7;
|
|
default:
|
|
unreachable("Unsupported bpp!");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#define GEN_AUX_MAP_ENTRY_Y_TILED_BIT (0x1ull << 52)
|
|
#define GEN_AUX_MAP_ENTRY_VALID_BIT 0x1ull
|
|
|
|
uint64_t
|
|
gen_aux_map_format_bits_for_isl_surf(const struct isl_surf *isl_surf)
|
|
{
|
|
const struct isl_format_layout *fmtl =
|
|
isl_format_get_layout(isl_surf->format);
|
|
|
|
uint16_t bpp = fmtl->bpb;
|
|
assert(fmtl->bw == 1 && fmtl->bh == 1 && fmtl->bd == 1);
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP entry %s, bpp=%d\n",
|
|
isl_format_get_name(isl_surf->format), bpp);
|
|
|
|
assert(isl_tiling_is_any_y(isl_surf->tiling));
|
|
|
|
uint64_t format_bits =
|
|
((uint64_t)get_format_encoding(isl_surf) << 58) |
|
|
((uint64_t)get_bpp_encoding(bpp) << 54) |
|
|
GEN_AUX_MAP_ENTRY_Y_TILED_BIT;
|
|
|
|
assert((format_bits & GEN_AUX_MAP_FORMAT_BITS_MASK) == format_bits);
|
|
|
|
return format_bits;
|
|
}
|
|
|
|
static void
|
|
get_aux_entry(struct gen_aux_map_context *ctx, uint64_t address,
|
|
uint32_t *l1_index_out, uint64_t *l1_entry_addr_out,
|
|
uint64_t **l1_entry_map_out)
|
|
{
|
|
uint32_t l3_index = (address >> 36) & 0xfff;
|
|
uint64_t *l3_entry = &ctx->level3_map[l3_index];
|
|
|
|
uint64_t *l2_map;
|
|
if ((*l3_entry & GEN_AUX_MAP_ENTRY_VALID_BIT) == 0) {
|
|
uint64_t l2_gpu;
|
|
if (add_sub_table(ctx, 32 * 1024, 32 * 1024, &l2_gpu, &l2_map)) {
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP L3[0x%x]: 0x%"PRIx64", map=%p\n",
|
|
l3_index, l2_gpu, l2_map);
|
|
} else {
|
|
unreachable("Failed to add L2 Aux-Map Page Table!");
|
|
}
|
|
*l3_entry = (l2_gpu & 0xffffffff8000ULL) | 1;
|
|
} else {
|
|
uint64_t l2_addr = gen_canonical_address(*l3_entry & ~0x7fffULL);
|
|
l2_map = get_u64_entry_ptr(ctx, l2_addr);
|
|
}
|
|
uint32_t l2_index = (address >> 24) & 0xfff;
|
|
uint64_t *l2_entry = &l2_map[l2_index];
|
|
|
|
uint64_t l1_addr, *l1_map;
|
|
if ((*l2_entry & GEN_AUX_MAP_ENTRY_VALID_BIT) == 0) {
|
|
if (add_sub_table(ctx, 8 * 1024, 8 * 1024, &l1_addr, &l1_map)) {
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP L2[0x%x]: 0x%"PRIx64", map=%p\n",
|
|
l2_index, l1_addr, l1_map);
|
|
} else {
|
|
unreachable("Failed to add L1 Aux-Map Page Table!");
|
|
}
|
|
*l2_entry = (l1_addr & 0xffffffffe000ULL) | 1;
|
|
} else {
|
|
l1_addr = gen_canonical_address(*l2_entry & ~0x1fffULL);
|
|
l1_map = get_u64_entry_ptr(ctx, l1_addr);
|
|
}
|
|
uint32_t l1_index = (address >> 16) & 0xff;
|
|
if (l1_index_out)
|
|
*l1_index_out = l1_index;
|
|
if (l1_entry_addr_out)
|
|
*l1_entry_addr_out = l1_addr + l1_index * sizeof(*l1_map);
|
|
if (l1_entry_map_out)
|
|
*l1_entry_map_out = &l1_map[l1_index];
|
|
}
|
|
|
|
static void
|
|
add_mapping(struct gen_aux_map_context *ctx, uint64_t address,
|
|
uint64_t aux_address, uint64_t format_bits,
|
|
bool *state_changed)
|
|
{
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP 0x%"PRIx64" => 0x%"PRIx64"\n", address,
|
|
aux_address);
|
|
|
|
uint32_t l1_index;
|
|
uint64_t *l1_entry;
|
|
get_aux_entry(ctx, address, &l1_index, NULL, &l1_entry);
|
|
|
|
const uint64_t l1_data =
|
|
(aux_address & GEN_AUX_MAP_ADDRESS_MASK) |
|
|
format_bits |
|
|
GEN_AUX_MAP_ENTRY_VALID_BIT;
|
|
|
|
const uint64_t current_l1_data = *l1_entry;
|
|
if ((current_l1_data & GEN_AUX_MAP_ENTRY_VALID_BIT) == 0) {
|
|
assert((aux_address & 0xffULL) == 0);
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP L1[0x%x] 0x%"PRIx64" -> 0x%"PRIx64"\n",
|
|
l1_index, current_l1_data, l1_data);
|
|
/**
|
|
* We use non-zero bits in 63:1 to indicate the entry had been filled
|
|
* previously. If these bits are non-zero and they don't exactly match
|
|
* what we want to program into the entry, then we must force the
|
|
* aux-map tables to be flushed.
|
|
*/
|
|
if (current_l1_data != 0 && \
|
|
(current_l1_data | GEN_AUX_MAP_ENTRY_VALID_BIT) != l1_data)
|
|
*state_changed = true;
|
|
*l1_entry = l1_data;
|
|
} else {
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP L1[0x%x] is already marked valid!\n",
|
|
l1_index);
|
|
assert(*l1_entry == l1_data);
|
|
}
|
|
}
|
|
|
|
uint64_t *
|
|
gen_aux_map_get_entry(struct gen_aux_map_context *ctx,
|
|
uint64_t address,
|
|
uint64_t *entry_address)
|
|
{
|
|
pthread_mutex_lock(&ctx->mutex);
|
|
uint64_t *l1_entry_map;
|
|
get_aux_entry(ctx, address, NULL, entry_address, &l1_entry_map);
|
|
pthread_mutex_unlock(&ctx->mutex);
|
|
|
|
return l1_entry_map;
|
|
}
|
|
|
|
void
|
|
gen_aux_map_add_mapping(struct gen_aux_map_context *ctx, uint64_t address,
|
|
uint64_t aux_address, uint64_t main_size_B,
|
|
uint64_t format_bits)
|
|
{
|
|
bool state_changed = false;
|
|
pthread_mutex_lock(&ctx->mutex);
|
|
uint64_t map_addr = address;
|
|
uint64_t dest_aux_addr = aux_address;
|
|
assert(align64(address, GEN_AUX_MAP_MAIN_PAGE_SIZE) == address);
|
|
assert(align64(aux_address, GEN_AUX_MAP_AUX_PAGE_SIZE) == aux_address);
|
|
while (map_addr - address < main_size_B) {
|
|
add_mapping(ctx, map_addr, dest_aux_addr, format_bits, &state_changed);
|
|
map_addr += GEN_AUX_MAP_MAIN_PAGE_SIZE;
|
|
dest_aux_addr += GEN_AUX_MAP_AUX_PAGE_SIZE;
|
|
}
|
|
pthread_mutex_unlock(&ctx->mutex);
|
|
if (state_changed)
|
|
p_atomic_inc(&ctx->state_num);
|
|
}
|
|
|
|
void
|
|
gen_aux_map_add_image(struct gen_aux_map_context *ctx,
|
|
const struct isl_surf *isl_surf, uint64_t address,
|
|
uint64_t aux_address)
|
|
{
|
|
gen_aux_map_add_mapping(ctx, address, aux_address, isl_surf->size_B,
|
|
gen_aux_map_format_bits_for_isl_surf(isl_surf));
|
|
}
|
|
|
|
/**
|
|
* We mark the leaf entry as invalid, but we don't attempt to cleanup the
|
|
* other levels of translation mappings. Since we attempt to re-use VMA
|
|
* ranges, hopefully this will not lead to unbounded growth of the translation
|
|
* tables.
|
|
*/
|
|
static void
|
|
remove_mapping(struct gen_aux_map_context *ctx, uint64_t address,
|
|
bool *state_changed)
|
|
{
|
|
uint32_t l3_index = (address >> 36) & 0xfff;
|
|
uint64_t *l3_entry = &ctx->level3_map[l3_index];
|
|
|
|
uint64_t *l2_map;
|
|
if ((*l3_entry & GEN_AUX_MAP_ENTRY_VALID_BIT) == 0) {
|
|
return;
|
|
} else {
|
|
uint64_t l2_addr = gen_canonical_address(*l3_entry & ~0x7fffULL);
|
|
l2_map = get_u64_entry_ptr(ctx, l2_addr);
|
|
}
|
|
uint32_t l2_index = (address >> 24) & 0xfff;
|
|
uint64_t *l2_entry = &l2_map[l2_index];
|
|
|
|
uint64_t *l1_map;
|
|
if ((*l2_entry & GEN_AUX_MAP_ENTRY_VALID_BIT) == 0) {
|
|
return;
|
|
} else {
|
|
uint64_t l1_addr = gen_canonical_address(*l2_entry & ~0x1fffULL);
|
|
l1_map = get_u64_entry_ptr(ctx, l1_addr);
|
|
}
|
|
uint32_t l1_index = (address >> 16) & 0xff;
|
|
uint64_t *l1_entry = &l1_map[l1_index];
|
|
|
|
const uint64_t current_l1_data = *l1_entry;
|
|
const uint64_t l1_data = current_l1_data & ~1ull;
|
|
|
|
if ((current_l1_data & GEN_AUX_MAP_ENTRY_VALID_BIT) == 0) {
|
|
return;
|
|
} else {
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP [0x%x][0x%x][0x%x] L1 entry removed!\n",
|
|
l3_index, l2_index, l1_index);
|
|
/**
|
|
* We use non-zero bits in 63:1 to indicate the entry had been filled
|
|
* previously. In the unlikely event that these are all zero, we force a
|
|
* flush of the aux-map tables.
|
|
*/
|
|
if (unlikely(l1_data == 0))
|
|
*state_changed = true;
|
|
*l1_entry = l1_data;
|
|
}
|
|
}
|
|
|
|
void
|
|
gen_aux_map_unmap_range(struct gen_aux_map_context *ctx, uint64_t address,
|
|
uint64_t size)
|
|
{
|
|
bool state_changed = false;
|
|
pthread_mutex_lock(&ctx->mutex);
|
|
if (aux_map_debug)
|
|
fprintf(stderr, "AUX-MAP remove 0x%"PRIx64"-0x%"PRIx64"\n", address,
|
|
address + size);
|
|
|
|
uint64_t map_addr = address;
|
|
assert(align64(address, GEN_AUX_MAP_MAIN_PAGE_SIZE) == address);
|
|
while (map_addr - address < size) {
|
|
remove_mapping(ctx, map_addr, &state_changed);
|
|
map_addr += 64 * 1024;
|
|
}
|
|
pthread_mutex_unlock(&ctx->mutex);
|
|
if (state_changed)
|
|
p_atomic_inc(&ctx->state_num);
|
|
}
|
|
|
|
uint32_t
|
|
gen_aux_map_get_num_buffers(struct gen_aux_map_context *ctx)
|
|
{
|
|
return p_atomic_read(&ctx->num_buffers);
|
|
}
|
|
|
|
void
|
|
gen_aux_map_fill_bos(struct gen_aux_map_context *ctx, void **driver_bos,
|
|
uint32_t max_bos)
|
|
{
|
|
assert(p_atomic_read(&ctx->num_buffers) >= max_bos);
|
|
uint32_t i = 0;
|
|
list_for_each_entry(struct aux_map_buffer, buf, &ctx->buffers, link) {
|
|
if (i >= max_bos)
|
|
return;
|
|
driver_bos[i++] = buf->buffer->driver_bo;
|
|
}
|
|
}
|