2019-12-09 20:54:09 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2019 Collabora, Ltd.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <xf86drm.h>
|
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
#include "drm-uapi/panfrost_drm.h"
|
2020-03-24 17:40:12 +00:00
|
|
|
#include "util/hash_table.h"
|
2022-12-23 21:58:38 +00:00
|
|
|
#include "util/macros.h"
|
|
|
|
#include "util/u_math.h"
|
2020-03-24 17:40:12 +00:00
|
|
|
#include "util/u_thread.h"
|
|
|
|
#include "pan_bo.h"
|
2022-12-23 21:58:38 +00:00
|
|
|
#include "pan_device.h"
|
|
|
|
#include "pan_encoder.h"
|
2020-08-12 22:45:05 +01:00
|
|
|
#include "pan_texture.h"
|
2021-01-29 21:26:57 +00:00
|
|
|
#include "pan_util.h"
|
2022-12-23 21:58:38 +00:00
|
|
|
#include "wrap.h"
|
2019-12-09 20:54:09 +00:00
|
|
|
|
2022-01-26 00:15:26 +00:00
|
|
|
/* Fixed "minimum revisions" */
|
2022-12-23 21:58:38 +00:00
|
|
|
#define NO_ANISO (~0)
|
2022-01-26 00:15:26 +00:00
|
|
|
#define HAS_ANISO (0)
|
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
#define MODEL(gpu_id_, shortname, counters_, min_rev_anisotropic_, tib_size_, \
|
|
|
|
quirks_) \
|
|
|
|
{ \
|
|
|
|
.gpu_id = gpu_id_, .name = "Mali-" shortname " (Panfrost)", \
|
|
|
|
.performance_counters = counters_, \
|
|
|
|
.min_rev_anisotropic = min_rev_anisotropic_, \
|
|
|
|
.tilebuffer_size = tib_size_, .quirks = quirks_, \
|
|
|
|
}
|
2022-01-26 00:15:26 +00:00
|
|
|
|
|
|
|
/* Table of supported Mali GPUs */
|
2022-12-23 02:22:15 +00:00
|
|
|
/* clang-format off */
|
2022-01-26 00:15:26 +00:00
|
|
|
const struct panfrost_model panfrost_model_list[] = {
|
2022-12-23 02:22:15 +00:00
|
|
|
MODEL(0x620, "T620", "T62x", NO_ANISO, 8192, {}),
|
|
|
|
MODEL(0x720, "T720", "T72x", NO_ANISO, 8192, { .no_hierarchical_tiling = true }),
|
|
|
|
MODEL(0x750, "T760", "T76x", NO_ANISO, 8192, {}),
|
|
|
|
MODEL(0x820, "T820", "T82x", NO_ANISO, 8192, { .no_hierarchical_tiling = true }),
|
|
|
|
MODEL(0x830, "T830", "T83x", NO_ANISO, 8192, { .no_hierarchical_tiling = true }),
|
|
|
|
MODEL(0x860, "T860", "T86x", NO_ANISO, 8192, {}),
|
|
|
|
MODEL(0x880, "T880", "T88x", NO_ANISO, 8192, {}),
|
|
|
|
|
|
|
|
MODEL(0x6000, "G71", "TMIx", NO_ANISO, 8192, {}),
|
|
|
|
MODEL(0x6221, "G72", "THEx", 0x0030 /* r0p3 */, 16384, {}),
|
|
|
|
MODEL(0x7090, "G51", "TSIx", 0x1010 /* r1p1 */, 16384, {}),
|
|
|
|
MODEL(0x7093, "G31", "TDVx", HAS_ANISO, 16384, {}),
|
|
|
|
MODEL(0x7211, "G76", "TNOx", HAS_ANISO, 16384, {}),
|
|
|
|
MODEL(0x7212, "G52", "TGOx", HAS_ANISO, 16384, {}),
|
|
|
|
MODEL(0x7402, "G52 r1", "TGOx", HAS_ANISO, 16384, {}),
|
|
|
|
MODEL(0x9093, "G57", "TNAx", HAS_ANISO, 16384, {}),
|
2022-01-26 00:15:26 +00:00
|
|
|
};
|
2022-12-23 02:22:15 +00:00
|
|
|
/* clang-format on */
|
2022-01-26 00:15:26 +00:00
|
|
|
|
|
|
|
#undef NO_ANISO
|
|
|
|
#undef HAS_ANISO
|
|
|
|
#undef MODEL
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up a supported model by its GPU ID, or return NULL if the model is not
|
|
|
|
* supported at this time.
|
|
|
|
*/
|
|
|
|
const struct panfrost_model *
|
|
|
|
panfrost_get_model(uint32_t gpu_id)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(panfrost_model_list); ++i) {
|
|
|
|
if (panfrost_model_list[i].gpu_id == gpu_id)
|
|
|
|
return &panfrost_model_list[i];
|
|
|
|
}
|
2022-01-26 00:15:26 +00:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
return NULL;
|
2022-01-26 00:15:26 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 20:54:09 +00:00
|
|
|
/* Abstraction over the raw drm_panfrost_get_param ioctl for fetching
|
|
|
|
* information about devices */
|
|
|
|
|
|
|
|
static __u64
|
2022-12-23 21:58:38 +00:00
|
|
|
panfrost_query_raw(int fd, enum drm_panfrost_param param, bool required,
|
|
|
|
unsigned default_value)
|
2019-12-09 20:54:09 +00:00
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
struct drm_panfrost_get_param get_param = {
|
|
|
|
0,
|
|
|
|
};
|
|
|
|
ASSERTED int ret;
|
2019-12-09 20:54:09 +00:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
get_param.param = param;
|
|
|
|
ret = drmIoctl(fd, DRM_IOCTL_PANFROST_GET_PARAM, &get_param);
|
2019-12-09 20:54:09 +00:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
if (ret) {
|
|
|
|
assert(!required);
|
|
|
|
return default_value;
|
|
|
|
}
|
2019-12-09 20:54:09 +00:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
return get_param.value;
|
2019-12-09 20:54:09 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 22:20:27 +01:00
|
|
|
static unsigned
|
2019-12-09 20:54:09 +00:00
|
|
|
panfrost_query_gpu_version(int fd)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
return panfrost_query_raw(fd, DRM_PANFROST_PARAM_GPU_PROD_ID, true, 0);
|
2019-12-09 20:54:09 +00:00
|
|
|
}
|
|
|
|
|
2020-12-20 04:01:59 +00:00
|
|
|
static unsigned
|
|
|
|
panfrost_query_gpu_revision(int fd)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
return panfrost_query_raw(fd, DRM_PANFROST_PARAM_GPU_REVISION, true, 0);
|
2020-12-20 04:01:59 +00:00
|
|
|
}
|
|
|
|
|
2022-05-25 19:34:39 +01:00
|
|
|
unsigned
|
|
|
|
panfrost_query_l2_slices(const struct panfrost_device *dev)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
/* Query MEM_FEATURES register */
|
|
|
|
uint32_t mem_features =
|
|
|
|
panfrost_query_raw(dev->fd, DRM_PANFROST_PARAM_MEM_FEATURES, true, 0);
|
2022-05-25 19:34:39 +01:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
/* L2_SLICES is MEM_FEATURES[11:8] minus(1) */
|
|
|
|
return ((mem_features >> 8) & 0xF) + 1;
|
2022-05-25 19:34:39 +01:00
|
|
|
}
|
|
|
|
|
2021-06-16 18:28:58 +01:00
|
|
|
static struct panfrost_tiler_features
|
|
|
|
panfrost_query_tiler_features(int fd)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
/* Default value (2^9 bytes and 8 levels) to match old behaviour */
|
|
|
|
uint32_t raw =
|
|
|
|
panfrost_query_raw(fd, DRM_PANFROST_PARAM_TILER_FEATURES, false, 0x809);
|
|
|
|
|
|
|
|
/* Bin size is log2 in the first byte, max levels in the second byte */
|
|
|
|
return (struct panfrost_tiler_features){
|
|
|
|
.bin_size = (1 << (raw & BITFIELD_MASK(5))),
|
|
|
|
.max_levels = (raw >> 8) & BITFIELD_MASK(4),
|
|
|
|
};
|
2021-06-16 18:28:58 +01:00
|
|
|
}
|
|
|
|
|
2020-10-21 22:20:27 +01:00
|
|
|
static unsigned
|
panfrost: Separate core ID range from core count
To query the core count, the hardware has a SHADERS_PRESENT register containing
a mask of shader cores connected. The core count equals the number of 1-bits,
regardless of placement. This value is useful for public consumption (like
in clinfo).
However, internally we are interested in the range of core IDs.
We usually query core count to determine how many cores to allocate various
per-core buffers for (performance counters, occlusion queries, and the stack).
In each case, the hardware writes at the index of its core ID, so we have to
allocate enough for entire range of core IDs. If the core mask is
discontiguous, this necessarily overallocates.
Rename the existing core_count to core_id_range, better reflecting its
definition and purpose, and repurpose core_count for the actual core count.
Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17265>
2022-06-24 22:43:09 +01:00
|
|
|
panfrost_query_core_count(int fd, unsigned *core_id_range)
|
2019-12-09 20:54:09 +00:00
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
/* On older kernels, worst-case to 16 cores */
|
2019-12-09 20:54:09 +00:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
unsigned mask =
|
|
|
|
panfrost_query_raw(fd, DRM_PANFROST_PARAM_SHADER_PRESENT, false, 0xffff);
|
2019-12-09 20:54:09 +00:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
/* Some cores might be absent. In some cases, we care
|
|
|
|
* about the range of core IDs (that is, the greatest core ID + 1). If
|
|
|
|
* the core mask is contiguous, this equals the core count.
|
|
|
|
*/
|
|
|
|
*core_id_range = util_last_bit(mask);
|
2021-01-07 23:22:54 +00:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
/* The actual core count skips overs the gaps */
|
|
|
|
return util_bitcount(mask);
|
2019-12-09 20:54:09 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 15:30:36 +01:00
|
|
|
static unsigned
|
|
|
|
panfrost_query_thread_tls_alloc(int fd, unsigned major)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
unsigned tls =
|
|
|
|
panfrost_query_raw(fd, DRM_PANFROST_PARAM_THREAD_TLS_ALLOC, false, 0);
|
2020-02-25 20:34:51 +00:00
|
|
|
|
2022-11-30 16:53:12 +00:00
|
|
|
return (tls > 0) ? tls : panfrost_max_thread_count(major, 0);
|
2019-12-09 20:54:09 +00:00
|
|
|
}
|
|
|
|
|
2020-07-10 15:42:24 +01:00
|
|
|
static uint32_t
|
|
|
|
panfrost_query_compressed_formats(int fd)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
/* If unspecified, assume ASTC/ETC only. Factory default for Juno, and
|
|
|
|
* should exist on any Mali configuration. All hardware should report
|
|
|
|
* these texture formats but the kernel might not be new enough. */
|
|
|
|
|
|
|
|
uint32_t default_set = (1 << MALI_ETC2_RGB8) | (1 << MALI_ETC2_R11_UNORM) |
|
|
|
|
(1 << MALI_ETC2_RGBA8) | (1 << MALI_ETC2_RG11_UNORM) |
|
|
|
|
(1 << MALI_ETC2_R11_SNORM) |
|
|
|
|
(1 << MALI_ETC2_RG11_SNORM) |
|
|
|
|
(1 << MALI_ETC2_RGB8A1) | (1 << MALI_ASTC_3D_LDR) |
|
|
|
|
(1 << MALI_ASTC_3D_HDR) | (1 << MALI_ASTC_2D_LDR) |
|
|
|
|
(1 << MALI_ASTC_2D_HDR);
|
|
|
|
|
|
|
|
return panfrost_query_raw(fd, DRM_PANFROST_PARAM_TEXTURE_FEATURES0, false,
|
|
|
|
default_set);
|
2020-07-10 15:42:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* DRM_PANFROST_PARAM_TEXTURE_FEATURES0 will return a bitmask of supported
|
|
|
|
* compressed formats, so we offer a helper to test if a format is supported */
|
|
|
|
|
|
|
|
bool
|
|
|
|
panfrost_supports_compressed_format(struct panfrost_device *dev, unsigned fmt)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
if (MALI_EXTRACT_TYPE(fmt) != MALI_FORMAT_COMPRESSED)
|
|
|
|
return true;
|
2020-07-10 15:42:24 +01:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
unsigned idx = fmt & ~MALI_FORMAT_COMPRESSED;
|
|
|
|
assert(idx < 32);
|
2020-07-10 15:42:24 +01:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
return dev->compressed_formats & (1 << idx);
|
2020-07-10 15:42:24 +01:00
|
|
|
}
|
|
|
|
|
2021-10-05 21:01:00 +01:00
|
|
|
/* Check for AFBC hardware support. AFBC is introduced in v5. Implementations
|
|
|
|
* may omit it, signaled as a nonzero value in the AFBC_FEATURES property. */
|
|
|
|
|
|
|
|
static bool
|
|
|
|
panfrost_query_afbc(int fd, unsigned arch)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
unsigned reg =
|
|
|
|
panfrost_query_raw(fd, DRM_PANFROST_PARAM_AFBC_FEATURES, false, 0);
|
2021-10-05 21:01:00 +01:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
return (arch >= 5) && (reg == 0);
|
2021-10-05 21:01:00 +01:00
|
|
|
}
|
|
|
|
|
2022-07-07 23:39:17 +01:00
|
|
|
/*
|
|
|
|
* To pipeline multiple tiles, a given tile may use at most half of the tile
|
|
|
|
* buffer. This function returns the optimal size (assuming pipelining).
|
|
|
|
*
|
|
|
|
* For Mali-G510 and Mali-G310, we will need extra logic to query the tilebuffer
|
|
|
|
* size for the particular variant. The CORE_FEATURES register might help.
|
|
|
|
*/
|
|
|
|
static unsigned
|
|
|
|
panfrost_query_optimal_tib_size(const struct panfrost_device *dev)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
/* Preconditions ensure the returned value is a multiple of 1 KiB, the
|
|
|
|
* granularity of the colour buffer allocation field.
|
|
|
|
*/
|
|
|
|
assert(dev->model->tilebuffer_size >= 2048);
|
|
|
|
assert(util_is_power_of_two_nonzero(dev->model->tilebuffer_size));
|
2022-07-07 23:39:17 +01:00
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
return dev->model->tilebuffer_size / 2;
|
2022-07-07 23:39:17 +01:00
|
|
|
}
|
|
|
|
|
2020-03-24 17:40:12 +00:00
|
|
|
void
|
|
|
|
panfrost_open_device(void *memctx, int fd, struct panfrost_device *dev)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
dev->fd = fd;
|
|
|
|
dev->memctx = memctx;
|
|
|
|
dev->gpu_id = panfrost_query_gpu_version(fd);
|
|
|
|
dev->arch = pan_arch(dev->gpu_id);
|
|
|
|
dev->kernel_version = drmGetVersion(fd);
|
|
|
|
dev->revision = panfrost_query_gpu_revision(fd);
|
|
|
|
dev->model = panfrost_get_model(dev->gpu_id);
|
|
|
|
|
2023-03-30 04:25:05 +01:00
|
|
|
if (!dev->kernel_version)
|
|
|
|
return;
|
|
|
|
|
2022-12-23 21:58:38 +00:00
|
|
|
/* If we don't recognize the model, bail early */
|
|
|
|
if (!dev->model)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dev->core_count = panfrost_query_core_count(fd, &dev->core_id_range);
|
|
|
|
dev->thread_tls_alloc = panfrost_query_thread_tls_alloc(fd, dev->arch);
|
|
|
|
dev->optimal_tib_size = panfrost_query_optimal_tib_size(dev);
|
|
|
|
dev->compressed_formats = panfrost_query_compressed_formats(fd);
|
|
|
|
dev->tiler_features = panfrost_query_tiler_features(fd);
|
|
|
|
dev->has_afbc = panfrost_query_afbc(fd, dev->arch);
|
|
|
|
|
|
|
|
if (dev->arch <= 6)
|
|
|
|
dev->formats = panfrost_pipe_format_v6;
|
|
|
|
else if (dev->arch <= 7)
|
|
|
|
dev->formats = panfrost_pipe_format_v7;
|
|
|
|
else
|
|
|
|
dev->formats = panfrost_pipe_format_v9;
|
|
|
|
|
|
|
|
util_sparse_array_init(&dev->bo_map, sizeof(struct panfrost_bo), 512);
|
|
|
|
|
|
|
|
pthread_mutex_init(&dev->bo_cache.lock, NULL);
|
|
|
|
list_inithead(&dev->bo_cache.lru);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(dev->bo_cache.buckets); ++i)
|
|
|
|
list_inithead(&dev->bo_cache.buckets[i]);
|
|
|
|
|
|
|
|
/* Initialize pandecode before we start allocating */
|
|
|
|
if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC))
|
|
|
|
pandecode_initialize(!(dev->debug & PAN_DBG_TRACE));
|
|
|
|
|
|
|
|
/* Tiler heap is internally required by the tiler, which can only be
|
|
|
|
* active for a single job chain at once, so a single heap can be
|
|
|
|
* shared across batches/contextes */
|
|
|
|
|
|
|
|
dev->tiler_heap = panfrost_bo_create(
|
|
|
|
dev, 128 * 1024 * 1024, PAN_BO_INVISIBLE | PAN_BO_GROWABLE, "Tiler heap");
|
|
|
|
|
|
|
|
pthread_mutex_init(&dev->submit_lock, NULL);
|
|
|
|
|
|
|
|
/* Done once on init */
|
|
|
|
panfrost_upload_sample_positions(dev);
|
2020-03-24 17:40:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
panfrost_close_device(struct panfrost_device *dev)
|
|
|
|
{
|
2022-12-23 21:58:38 +00:00
|
|
|
/* If we don't recognize the model, the rest of the device won't exist,
|
|
|
|
* we will have early-exited the device open.
|
|
|
|
*/
|
|
|
|
if (dev->model) {
|
|
|
|
pthread_mutex_destroy(&dev->submit_lock);
|
|
|
|
panfrost_bo_unreference(dev->tiler_heap);
|
2023-02-16 22:12:04 +00:00
|
|
|
panfrost_bo_unreference(dev->sample_positions);
|
2022-12-23 21:58:38 +00:00
|
|
|
panfrost_bo_cache_evict_all(dev);
|
|
|
|
pthread_mutex_destroy(&dev->bo_cache.lock);
|
|
|
|
util_sparse_array_finish(&dev->bo_map);
|
|
|
|
}
|
|
|
|
|
|
|
|
drmFreeVersion(dev->kernel_version);
|
|
|
|
close(dev->fd);
|
2020-03-24 17:40:12 +00:00
|
|
|
}
|