This commit is contained in:
elwrcl committed 2026-06-06 13:25:15 +03:00
1 parent 04d4dc8b09
commit 818cab85dc
12511 files changed
+6156641

No files matched your search

+348
View File
@@ -0,0 +1,348 @@
# Copyright © 2023 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.
import argparse
import collections
import json
import os
import sys
from mako.template import Template
HEADER_TEMPLATE = Template("""\
/*
* Copyright © 2023 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.
*
*/
#ifndef INTEL_WA_H
#define INTEL_WA_H
#ifndef __OPENCL_VERSION__
#include "util/macros.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __OPENCL_VERSION__
struct intel_device_info;
void intel_device_info_init_was(struct intel_device_info *devinfo);
#endif
enum intel_wa_steppings {
% for a in stepping_enum:
INTEL_STEPPING_${a},
% endfor
INTEL_STEPPING_RELEASE
};
enum intel_workaround_id {
% for a in wa_def:
INTEL_WA_${a},
% endfor
INTEL_WA_NUM
};
/* These defines apply workarounds to a subset of platforms within a graphics
* generation. They must be used in conjunction with intel_needs_workaround()
* to check platform details. Use these macros to compile out genxml code on
* generations where it can never execute. Whenever possible, prefer use of
* INTEL_NEEDS_WA_{num} instead of INTEL_WA_{num}_GFX_VER
*/
% for a in wa_def:
#define INTEL_WA_${a}_GFX_VER ${wa_macro[a]}
% endfor
/* These defines may be used to compile out genxml workaround implementations
* using #if guards. If a definition has been 'poisoned' below, then it applies to a
* subset of a graphics generation. In that case, use INTEL_WA_{NUM}_GFX_VER macros
* in conjunction with calls to intel_needs_workaround().
*/
% for a in partial_gens:
% if partial_gens[a]:
PRAGMA_POISON(INTEL_NEEDS_WA_${a})
% else:
#define INTEL_NEEDS_WA_${a} INTEL_WA_${a}_GFX_VER
% endif
% endfor
#define INTEL_ALL_WA ${"\\\\"}
% for wa_id in wa_def:
INTEL_WA(${wa_id}), ${"\\\\"}
% endfor
#ifdef __cplusplus
}
#endif
#endif /* INTEL_WA_H */
""")
IMPL_TEMPLATE = Template("""\
/*
* Copyright © 2023 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "dev/intel_wa.h"
#include "dev/intel_device_info.h"
#include "util/bitset.h"
void intel_device_info_init_was(struct intel_device_info *devinfo)
{
switch(devinfo->platform) {
% for platform in platform_bugs:
case ${platform}:
% if platform in stepping_bugs:
switch(intel_device_info_wa_stepping(devinfo)) {
% for stepping, ids in stepping_bugs[platform].items():
case INTEL_STEPPING_${stepping}:
% for id in ids:
BITSET_SET(devinfo->workarounds, INTEL_WA_${id});
% endfor
break;
% endfor
default:
break;
}
% endif
% for id in platform_bugs[platform]:
BITSET_SET(devinfo->workarounds, INTEL_WA_${id});
% endfor
break;
% endfor
default:
/* unsupported platform */
break;
};
}
""")
def stepping_enums(wa_def):
"""provide a sorted list of all known steppings"""
stepping_enum = []
for bug in wa_def.values():
for platform_info in bug["mesa_platforms"].values():
steppings = platform_info["steppings"]
if steppings == "all":
continue
steppings = steppings.split("..")
for stepping in steppings:
stepping = stepping.upper()
if stepping and stepping != "None" and stepping not in stepping_enum:
stepping_enum.append(stepping)
return sorted(stepping_enum)
_PLATFORM_GFXVERS = {"INTEL_PLATFORM_BDW" : 80,
"INTEL_PLATFORM_CHV" : 80,
"INTEL_PLATFORM_SKL" : 90,
"INTEL_PLATFORM_BXT" : 90,
"INTEL_PLATFORM_KBL" : 90,
"INTEL_PLATFORM_GLK" : 90,
"INTEL_PLATFORM_CFL" : 90,
"INTEL_PLATFORM_ICL" : 110,
"INTEL_PLATFORM_EHL" : 110,
"INTEL_PLATFORM_TGL" : 120,
"INTEL_PLATFORM_RKL" : 120,
"INTEL_PLATFORM_DG1" : 120,
"INTEL_PLATFORM_ADL" : 120,
"INTEL_PLATFORM_RPL" : 120,
"INTEL_PLATFORM_DG2_G10" : 125,
"INTEL_PLATFORM_DG2_G11" : 125,
"INTEL_PLATFORM_DG2_G12" : 125,
"INTEL_PLATFORM_ATSM_G10" : 125,
"INTEL_PLATFORM_ATSM_G11" : 125,
"INTEL_PLATFORM_MTL_U" : 125,
"INTEL_PLATFORM_MTL_H" : 125,
"INTEL_PLATFORM_ARL_U" : 125,
"INTEL_PLATFORM_ARL_H" : 125,
"INTEL_PLATFORM_LNL" : 200,
"INTEL_PLATFORM_BMG" : 200,
"INTEL_PLATFORM_PTL" : 300,
"INTEL_PLATFORM_WCL" : 300,
"INTEL_PLATFORM_NVL_U" : 300,
"INTEL_PLATFORM_NVL_P" : 350,
}
def macro_versions(wa_def):
"""provide a map of workaround id -> GFX_VERx10 macro test"""
wa_macro = {}
for bug_id, bug in wa_def.items():
platforms = set()
for platform in bug["mesa_platforms"]:
gfxver = _PLATFORM_GFXVERS[platform]
if gfxver not in platforms:
platforms.add(gfxver)
if not platforms:
continue
ver_cmps = [f"(GFX_VERx10 == {platform})" for platform in sorted(platforms)]
wa_macro[bug_id] = ver_cmps[0]
if len(ver_cmps) > 1:
wa_macro[bug_id] = f"({' || '.join(ver_cmps)})"
return wa_macro
def partial_gens(wa_def):
"""provide a map of workaround id -> true/false, indicating whether the wa
applies to a subset of platforms in a generation"""
wa_partial_gen = {}
# map of gfxver -> set(all platforms for gfxver)
generations = collections.defaultdict(set)
for platform, gfxver in _PLATFORM_GFXVERS.items():
generations[gfxver].add(platform)
# map of platform -> set(all required platforms for gen completeness)
required_platforms = collections.defaultdict(set)
for gen_set in generations.values():
for platform in gen_set:
required_platforms[platform] = gen_set
for bug_id, bug in wa_def.items():
# for the given wa, create a set which includes all platforms that
# match any of the affected gfxver.
wa_required_for_completeness = set()
for platform in bug["mesa_platforms"]:
wa_required_for_completeness.update(required_platforms[platform])
# eliminate each platform specifically indicated by the WA, to see if
# are left over.
for platform, desc in bug["mesa_platforms"].items():
if desc["steppings"] == "all":
wa_required_for_completeness.remove(platform)
# if any platform remains in the required set, then this wa *partially*
# applies to one of the gfxvers.
wa_partial_gen[bug_id] = bool(wa_required_for_completeness)
return wa_partial_gen
def platform_was(wa_def):
"""provide a map of platform -> list of workarounds"""
platform_bugs = collections.defaultdict(list)
for workaround, bug in wa_def.items():
for platform, desc in bug["mesa_platforms"].items():
if desc["steppings"] != "all":
# stepping-specific workaround, not platform-wide
continue
platform_bugs[platform].append(workaround)
return platform_bugs
def stepping_was(wa_def, all_steppings):
"""provide a map of wa[platform][stepping] -> [ids]"""
stepping_bugs = collections.defaultdict(lambda: collections.defaultdict(list))
for workaround, bug in wa_def.items():
for platform, desc in bug["mesa_platforms"].items():
if desc["steppings"] == "all":
continue
first_stepping, fixed_stepping = desc["steppings"].split("..")
first_stepping = first_stepping.upper()
fixed_stepping = fixed_stepping.upper()
steppings = []
for step in all_steppings:
if step <first_stepping:
continue
if step >= fixed_stepping:
break
steppings.append(step)
for step in steppings:
u_step = step.upper()
stepping_bugs[platform][u_step].append(workaround)
stepping_bugs[platform][u_step].sort()
return stepping_bugs
def main():
"""writes c/h generated files to outdir"""
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("wa_file", type=str,
help="json data file with workaround definitions")
parser.add_argument("header_file", help="include file to generate")
parser.add_argument("impl_file", help="implementation file to generate")
args = parser.parse_args()
if not os.path.exists(args.wa_file):
print(f"Error: workaround definition not found: {args.wa_file}")
sys.exit(-1)
# json dictionary of workaround definitions
wa_def = {}
with open(args.wa_file, encoding='utf8') as wa_fh:
wa_def = json.load(wa_fh)
# detect unknown platforms
unknown_platforms = set()
for wa in wa_def.values():
for p in wa['mesa_platforms']:
if p not in _PLATFORM_GFXVERS:
unknown_platforms.add(p)
if unknown_platforms:
abbrev = map(lambda s: s.replace('INTEL_PLATFORM_', ''),
unknown_platforms)
raise Exception(f'warning: unknown platforms in {args.wa_file}: '
f'{", ".join(abbrev)}')
steppings = stepping_enums(wa_def)
with open(args.header_file, 'w', encoding='utf8') as header:
header.write(HEADER_TEMPLATE.render(wa_def=wa_def,
stepping_enum=steppings,
wa_macro=macro_versions(wa_def),
partial_gens=partial_gens(wa_def)))
with open(args.impl_file, 'w', encoding='utf8') as impl:
impl.write(IMPL_TEMPLATE.render(platform_bugs=platform_was(wa_def),
stepping_bugs=stepping_was(wa_def, steppings)))
main()
+644
View File
@@ -0,0 +1,644 @@
/*
* Copyright © 2023 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <string.h>
#include "intel/dev/i915/intel_device_info.h"
#include "intel/dev/intel_device_info.h"
#include "intel/dev/intel_hwconfig.h"
#include "intel/common/intel_gem.h"
#include "intel/common/i915/intel_gem.h"
#include "util/bitscan.h"
#include "util/log.h"
#include "util/os_misc.h"
#include "drm-uapi/i915_drm.h"
/* At some point in time, some people decided to redefine what topology means,
* from useful HW related information (slice, subslice, etc...), to much less
* useful generic stuff that no one cares about (a single slice with lots of
* subslices). Of course all of this was done without asking the people who
* defined the topology query in the first place, to solve a lack of
* information Gfx10+. This function is here to workaround the fact it's not
* possible to change people's mind even before this stuff goes upstream. Sad
* times...
*/
static void
update_from_single_slice_topology(struct intel_device_info *devinfo,
const struct drm_i915_query_topology_info *topology,
const struct drm_i915_query_topology_info *geom_topology)
{
/* An array of bit masks of the subslices available for 3D
* workloads, analogous to intel_device_info::subslice_masks. This
* may differ from the set of enabled subslices on XeHP+ platforms
* with compute-only subslices.
*/
uint8_t geom_subslice_masks[ARRAY_SIZE(devinfo->subslice_masks)] = { 0 };
assert(devinfo->verx10 >= 125);
intel_device_info_topology_reset_masks(devinfo);
assert(topology->max_slices == 1);
assert(topology->max_subslices > 0);
assert(topology->max_eus_per_subslice > 0);
/* i915 gives us only one slice so we have to rebuild that out of groups of
* 4 dualsubslices.
*/
devinfo->max_subslices_per_slice = 4;
devinfo->max_eus_per_subslice = 16;
devinfo->subslice_slice_stride = 1;
devinfo->eu_slice_stride = DIV_ROUND_UP(16 * 4, 8);
devinfo->eu_subslice_stride = DIV_ROUND_UP(16, 8);
for (uint32_t ss_idx = 0; ss_idx < topology->max_subslices; ss_idx++) {
const uint32_t s = ss_idx / 4;
const uint32_t ss = ss_idx % 4;
/* Determine whether ss_idx is enabled (ss_idx_available) and
* available for 3D workloads (geom_ss_idx_available), which may
* differ on XeHP+ if ss_idx is a compute-only DSS.
*/
const bool ss_idx_available =
(topology->data[topology->subslice_offset + ss_idx / 8] >>
(ss_idx % 8)) & 1;
const bool geom_ss_idx_available =
(geom_topology->data[geom_topology->subslice_offset + ss_idx / 8] >>
(ss_idx % 8)) & 1;
if (geom_ss_idx_available) {
assert(ss_idx_available);
geom_subslice_masks[s * devinfo->subslice_slice_stride +
ss / 8] |= 1u << (ss % 8);
}
if (!ss_idx_available)
continue;
devinfo->max_slices = MAX2(devinfo->max_slices, s + 1);
devinfo->slice_masks |= 1u << s;
devinfo->subslice_masks[s * devinfo->subslice_slice_stride +
ss / 8] |= 1u << (ss % 8);
for (uint32_t eu = 0; eu < devinfo->max_eus_per_subslice; eu++) {
const bool eu_available =
(topology->data[topology->eu_offset +
ss_idx * topology->eu_stride +
eu / 8] >> (eu % 8)) & 1;
if (!eu_available)
continue;
devinfo->eu_masks[s * devinfo->eu_slice_stride +
ss * devinfo->eu_subslice_stride +
eu / 8] |= 1u << (eu % 8);
}
}
intel_device_info_topology_update_counts(devinfo);
intel_device_info_update_pixel_pipes(devinfo, geom_subslice_masks);
intel_device_info_update_l3_banks(devinfo);
}
static void
update_from_topology(struct intel_device_info *devinfo,
const struct drm_i915_query_topology_info *topology)
{
intel_device_info_topology_reset_masks(devinfo);
assert(topology->max_slices > 0);
assert(topology->max_subslices > 0);
assert(topology->max_eus_per_subslice > 0);
devinfo->subslice_slice_stride = topology->subslice_stride;
devinfo->eu_subslice_stride = DIV_ROUND_UP(topology->max_eus_per_subslice, 8);
devinfo->eu_slice_stride = topology->max_subslices * devinfo->eu_subslice_stride;
assert(sizeof(devinfo->slice_masks) >= DIV_ROUND_UP(topology->max_slices, 8));
memcpy(&devinfo->slice_masks, topology->data, DIV_ROUND_UP(topology->max_slices, 8));
devinfo->max_slices = topology->max_slices;
devinfo->max_subslices_per_slice = topology->max_subslices;
devinfo->max_eus_per_subslice = topology->max_eus_per_subslice;
uint32_t subslice_mask_len =
topology->max_slices * topology->subslice_stride;
assert(sizeof(devinfo->subslice_masks) >= subslice_mask_len);
memcpy(devinfo->subslice_masks, &topology->data[topology->subslice_offset],
subslice_mask_len);
uint32_t eu_mask_len =
topology->eu_stride * topology->max_subslices * topology->max_slices;
assert(sizeof(devinfo->eu_masks) >= eu_mask_len);
memcpy(devinfo->eu_masks, &topology->data[topology->eu_offset], eu_mask_len);
/* Now that all the masks are in place, update the counts. */
intel_device_info_topology_update_counts(devinfo);
intel_device_info_update_pixel_pipes(devinfo, devinfo->subslice_masks);
intel_device_info_update_l3_banks(devinfo);
}
/* Generate detailed mask from the I915_PARAM_SLICE_MASK,
* I915_PARAM_SUBSLICE_MASK & I915_PARAM_EU_TOTAL getparam.
*/
bool
intel_device_info_i915_update_from_masks(struct intel_device_info *devinfo, uint32_t slice_mask,
uint32_t subslice_mask, uint32_t n_eus)
{
struct drm_i915_query_topology_info *topology;
assert((slice_mask & 0xff) == slice_mask);
size_t data_length = 100;
topology = calloc(1, sizeof(*topology) + data_length);
if (!topology)
return false;
topology->max_slices = util_last_bit(slice_mask);
topology->max_subslices = util_last_bit(subslice_mask);
topology->subslice_offset = DIV_ROUND_UP(topology->max_slices, 8);
topology->subslice_stride = DIV_ROUND_UP(topology->max_subslices, 8);
uint32_t n_subslices = __builtin_popcount(slice_mask) *
__builtin_popcount(subslice_mask);
uint32_t max_eus_per_subslice = DIV_ROUND_UP(n_eus, n_subslices);
uint32_t eu_mask = (1U << max_eus_per_subslice) - 1;
topology->max_eus_per_subslice = max_eus_per_subslice;
topology->eu_offset = topology->subslice_offset +
topology->max_slices * DIV_ROUND_UP(topology->max_subslices, 8);
topology->eu_stride = DIV_ROUND_UP(max_eus_per_subslice, 8);
/* Set slice mask in topology */
for (int b = 0; b < topology->subslice_offset; b++)
topology->data[b] = (slice_mask >> (b * 8)) & 0xff;
for (int s = 0; s < topology->max_slices; s++) {
/* Set subslice mask in topology */
for (int b = 0; b < topology->subslice_stride; b++) {
int subslice_offset = topology->subslice_offset +
s * topology->subslice_stride + b;
topology->data[subslice_offset] = (subslice_mask >> (b * 8)) & 0xff;
}
/* Set eu mask in topology */
for (int ss = 0; ss < topology->max_subslices; ss++) {
for (int b = 0; b < topology->eu_stride; b++) {
int eu_offset = topology->eu_offset +
(s * topology->max_subslices + ss) * topology->eu_stride + b;
topology->data[eu_offset] = (eu_mask >> (b * 8)) & 0xff;
}
}
}
update_from_topology(devinfo, topology);
free(topology);
return true;
}
static bool
getparam(int fd, uint32_t param, int *value)
{
int tmp;
struct drm_i915_getparam gp = {
.param = param,
.value = &tmp,
};
int ret = intel_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
if (ret != 0)
return false;
*value = tmp;
return true;
}
static bool
get_context_param(int fd, uint32_t context, uint32_t param, uint64_t *value)
{
struct drm_i915_gem_context_param gp = {
.ctx_id = context,
.param = param,
};
int ret = intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &gp);
if (ret != 0)
return false;
*value = gp.value;
return true;
}
/**
* for gfx8/gfx9, SLICE_MASK/SUBSLICE_MASK can be used to compute the topology
* (kernel 4.13+)
*/
static bool
getparam_topology(struct intel_device_info *devinfo, int fd)
{
int slice_mask = 0;
if (!getparam(fd, I915_PARAM_SLICE_MASK, &slice_mask))
goto maybe_warn;
int n_eus;
if (!getparam(fd, I915_PARAM_EU_TOTAL, &n_eus))
goto maybe_warn;
int subslice_mask = 0;
if (!getparam(fd, I915_PARAM_SUBSLICE_MASK, &subslice_mask))
goto maybe_warn;
return intel_device_info_i915_update_from_masks(devinfo, slice_mask, subslice_mask, n_eus);
maybe_warn:
/* Only with Gfx8+ are we starting to see devices with fusing that can only
* be detected at runtime.
*/
if (devinfo->ver >= 8)
mesa_logw("Kernel 4.1 required to properly query GPU properties.");
return false;
}
/**
* preferred API for updating the topology in devinfo (kernel 4.17+)
*/
static bool
query_topology(struct intel_device_info *devinfo, int fd)
{
struct drm_i915_query_topology_info *topo_info =
intel_i915_query_alloc(fd, DRM_I915_QUERY_TOPOLOGY_INFO, NULL);
if (topo_info == NULL)
return false;
if (devinfo->verx10 >= 125) {
struct drm_i915_query_topology_info *geom_topo_info =
intel_i915_query_alloc(fd, DRM_I915_QUERY_GEOMETRY_SUBSLICES, NULL);
if (geom_topo_info == NULL) {
free(topo_info);
return false;
}
update_from_single_slice_topology(devinfo, topo_info, geom_topo_info);
free(geom_topo_info);
} else {
update_from_topology(devinfo, topo_info);
}
free(topo_info);
return true;
}
/**
* Reports memory region info, and allows buffers to target system-memory,
* and/or device local memory.
*/
bool
intel_device_info_i915_query_regions(struct intel_device_info *devinfo, int fd, bool update)
{
struct drm_i915_query_memory_regions *meminfo =
intel_i915_query_alloc(fd, DRM_I915_QUERY_MEMORY_REGIONS, NULL);
if (meminfo == NULL) {
/* If the memory region uAPI query is not available, try to generate some
* numbers out of os_* utils for sram only.
*/
return intel_device_info_compute_system_memory(devinfo, false);
}
for (int i = 0; i < meminfo->num_regions; i++) {
const struct drm_i915_memory_region_info *mem = &meminfo->regions[i];
switch (mem->region.memory_class) {
case I915_MEMORY_CLASS_SYSTEM: {
if (!update) {
devinfo->mem.sram.mem.klass = mem->region.memory_class;
devinfo->mem.sram.mem.instance = mem->region.memory_instance;
devinfo->mem.sram.mappable.size = mem->probed_size;
} else {
assert(devinfo->mem.sram.mem.klass == mem->region.memory_class);
assert(devinfo->mem.sram.mem.instance == mem->region.memory_instance);
assert(devinfo->mem.sram.mappable.size == mem->probed_size);
}
/* if running without elevated privileges i915 reports
* unallocated_size == probed_size
*/
devinfo->mem.sram.mappable.free = mem->unallocated_size;
break;
}
case I915_MEMORY_CLASS_DEVICE:
if (!update) {
devinfo->mem.vram.mem.klass = mem->region.memory_class;
devinfo->mem.vram.mem.instance = mem->region.memory_instance;
if (mem->probed_cpu_visible_size > 0) {
devinfo->mem.vram.mappable.size = mem->probed_cpu_visible_size;
devinfo->mem.vram.unmappable.size =
mem->probed_size - mem->probed_cpu_visible_size;
} else {
/* We are running on an older kernel without support for the
* small-bar uapi. These kernels only support systems where the
* entire vram is mappable.
*/
devinfo->mem.vram.mappable.size = mem->probed_size;
devinfo->mem.vram.unmappable.size = 0;
}
} else {
assert(devinfo->mem.vram.mem.klass == mem->region.memory_class);
assert(devinfo->mem.vram.mem.instance == mem->region.memory_instance);
assert((devinfo->mem.vram.mappable.size +
devinfo->mem.vram.unmappable.size) == mem->probed_size);
}
if (mem->unallocated_cpu_visible_size > 0) {
if (mem->unallocated_size != -1) {
devinfo->mem.vram.mappable.free = mem->unallocated_cpu_visible_size;
devinfo->mem.vram.unmappable.free =
mem->unallocated_size - mem->unallocated_cpu_visible_size;
}
} else {
/* We are running on an older kernel without support for the
* small-bar uapi. These kernels only support systems where the
* entire vram is mappable.
*/
if (mem->unallocated_size != -1) {
devinfo->mem.vram.mappable.free = mem->unallocated_size;
devinfo->mem.vram.unmappable.free = 0;
}
}
break;
default:
break;
}
}
free(meminfo);
devinfo->mem.use_class_instance = true;
return true;
}
static int
intel_get_aperture_size(int fd, uint64_t *size)
{
struct drm_i915_gem_get_aperture aperture = { 0 };
int ret = intel_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
if (ret == 0 && size)
*size = aperture.aper_size;
return ret;
}
static bool
has_bit6_swizzle(int fd)
{
struct drm_gem_close close;
struct drm_i915_gem_create gem_create = {
.size = 4096,
};
if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create)) {
UNREACHABLE("Failed to create GEM BO");
return false;
}
bool swizzled = false;
/* set_tiling overwrites the input on the error path, so we have to open
* code intel_ioctl.
*/
struct drm_i915_gem_set_tiling set_tiling = {
.handle = gem_create.handle,
.tiling_mode = I915_TILING_X,
.stride = 512,
};
if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) {
UNREACHABLE("Failed to set BO tiling");
goto close_and_return;
}
struct drm_i915_gem_get_tiling get_tiling = {
.handle = gem_create.handle,
};
if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling)) {
UNREACHABLE("Failed to get BO tiling");
goto close_and_return;
}
assert(get_tiling.tiling_mode == I915_TILING_X);
swizzled = get_tiling.swizzle_mode != I915_BIT_6_SWIZZLE_NONE;
close_and_return:
memset(&close, 0, sizeof(close));
close.handle = gem_create.handle;
intel_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
return swizzled;
}
static bool
has_get_tiling(int fd)
{
int ret;
struct drm_i915_gem_create gem_create = {
.size = 4096,
};
if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create)) {
UNREACHABLE("Failed to create GEM BO");
return false;
}
struct drm_i915_gem_get_tiling get_tiling = {
.handle = gem_create.handle,
};
ret = intel_ioctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling);
struct drm_gem_close close = {
.handle = gem_create.handle,
};
intel_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
return ret == 0;
}
static bool
has_userptr(int fd)
{
struct drm_i915_gem_userptr userptr = {
.user_ptr = 0,
.user_size = 0,
.flags = 0,
};
intel_ioctl(fd, DRM_IOCTL_I915_GEM_USERPTR, &userptr);
return errno == EINVAL;
}
static void
fixup_chv_device_info(struct intel_device_info *devinfo)
{
assert(devinfo->platform == INTEL_PLATFORM_CHV);
/* Cherryview is annoying. The number of EUs is depending on fusing and
* isn't determinable from the PCI ID alone. We default to the minimum
* available for that PCI ID and then compute the real value from the
* subslice information we get from the kernel.
*/
const uint32_t subslice_total = intel_device_info_subslice_total(devinfo);
const uint32_t eu_total = intel_device_info_eu_total(devinfo);
/* Logical CS threads = EUs per subslice * num threads per EU */
uint32_t max_cs_threads =
eu_total / subslice_total * devinfo->num_thread_per_eu;
/* Fuse configurations may give more threads than expected, never less. */
if (max_cs_threads > devinfo->max_cs_threads)
devinfo->max_cs_threads = max_cs_threads;
intel_device_info_update_cs_workgroup_threads(devinfo);
/* Braswell is even more annoying. Its marketing name isn't determinable
* from the PCI ID and is also dependent on fusing.
*/
if (devinfo->pci_device_id != 0x22B1)
return;
char *bsw_model;
switch (eu_total) {
case 16: bsw_model = "405"; break;
case 12: bsw_model = "400"; break;
default: bsw_model = " "; break;
}
char *needle = strstr(devinfo->name, "XXX");
assert(needle);
if (needle)
memcpy(needle, bsw_model, 3);
}
void *
intel_device_info_i915_query_hwconfig(int fd, int32_t *len)
{
return intel_i915_query_alloc(fd, DRM_I915_QUERY_HWCONFIG_BLOB, len);
}
bool intel_device_info_i915_get_info_from_fd(int fd, struct intel_device_info *devinfo)
{
void *hwconfig_blob;
int32_t len;
int val;
if (getparam(fd, I915_PARAM_CS_TIMESTAMP_FREQUENCY, &val))
devinfo->timestamp_frequency = val;
else if (devinfo->ver >= 10) {
mesa_loge("Kernel 4.15 required to read the CS timestamp frequency.");
return false;
}
if (!getparam(fd, I915_PARAM_REVISION, &devinfo->revision))
devinfo->revision = 0;
if (!query_topology(devinfo, fd)) {
if (devinfo->ver >= 10) {
/* topology uAPI required for CNL+ (kernel 4.17+) */
return false;
}
/* else use the kernel 4.13+ api for gfx8+. For older kernels, topology
* will be wrong, affecting GPU metrics. In this case, fail silently.
*/
getparam_topology(devinfo, fd);
}
hwconfig_blob = intel_device_info_i915_query_hwconfig(fd, &len);
if (hwconfig_blob) {
intel_hwconfig_process_table(devinfo, hwconfig_blob, len);
free(hwconfig_blob);
}
intel_device_info_i915_query_regions(devinfo, fd, false);
if (devinfo->platform == INTEL_PLATFORM_CHV)
fixup_chv_device_info(devinfo);
/* Broadwell PRM says:
*
* "Before Gfx8, there was a historical configuration control field to
* swizzle address bit[6] for in X/Y tiling modes. This was set in three
* different places: TILECTL[1:0], ARB_MODE[5:4], and
* DISP_ARB_CTL[14:13].
*
* For Gfx8 and subsequent generations, the swizzle fields are all
* reserved, and the CPU's memory controller performs all address
* swizzling modifications."
*/
devinfo->has_bit6_swizzle = devinfo->ver < 8 && has_bit6_swizzle(fd);
intel_get_aperture_size(fd, &devinfo->aperture_bytes);
get_context_param(fd, 0, I915_CONTEXT_PARAM_GTT_SIZE, &devinfo->gtt_size);
devinfo->has_tiling_uapi = has_get_tiling(fd);
devinfo->has_userptr_uapi = has_userptr(fd);
devinfo->has_madvise_purgeable = true;
devinfo->has_caching_uapi =
devinfo->platform < INTEL_PLATFORM_DG2_START && !devinfo->has_local_mem;
if (devinfo->ver > 12 || intel_device_info_is_mtl_or_arl(devinfo))
devinfo->has_set_pat_uapi = true;
if (getparam(fd, I915_PARAM_MMAP_GTT_VERSION, &val)) {
devinfo->has_mmap_offset = val >= 4;
devinfo->has_partial_mmap_offset = val >= 5;
}
if (getparam(fd, I915_PARAM_HAS_USERPTR_PROBE, &val))
devinfo->has_userptr_probe = val;
if (getparam(fd, I915_PARAM_HAS_CONTEXT_ISOLATION, &val))
devinfo->has_context_isolation = val;
if (getparam(fd, getparam(fd, I915_PARAM_HAS_CONTEXT_ISOLATION, &val), &val))
devinfo->supports_low_latency_hint = val == 1;
/* TODO: We might be able to reduce alignment to 4Kb on DG1. */
if (devinfo->verx10 >= 125)
devinfo->mem_alignment = 64 * 1024;
else if (devinfo->has_local_mem)
devinfo->mem_alignment = 64 * 1024;
else
devinfo->mem_alignment = 4096;
return true;
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright © 2023 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.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
struct intel_device_info;
bool
intel_device_info_i915_get_info_from_fd(int fd,
struct intel_device_info *devinfo);
bool
intel_device_info_i915_query_regions(struct intel_device_info *devinfo,
int fd, bool update);
bool
intel_device_info_i915_update_from_masks(struct intel_device_info *devinfo,
uint32_t slice_mask,
uint32_t subslice_mask,
uint32_t n_eus);
void *
intel_device_info_i915_query_hwconfig(int fd, int32_t *len);
+345
View File
@@ -0,0 +1,345 @@
/*
* Copyright 2003 VMware, Inc.
* Copyright © 2006 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.
*/
/**
* \file intel_debug.c
*
* Support for the INTEL_DEBUG environment variable, along with other
* miscellaneous debugging code.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dev/intel_debug.h"
#include "dev/intel_device_info.h"
#include "util/macros.h"
#include "util/u_debug.h"
#include "util/u_math.h"
#include "c11/threads.h"
BITSET_WORD intel_debug[BITSET_WORDS(INTEL_DEBUG_MAX)] = {0};
struct debug_control_bitset {
const char *string;
uint32_t range[2];
};
static const struct debug_control_bitset debug_control[] = {
#define OPT1(name, bit) \
{ .string = name, .range = { bit, bit }, }
#define OPT2(name, start, end) \
{ .string = name, .range = { start, end }, }
OPT1("tex", DEBUG_TEXTURE),
OPT1("blit", DEBUG_BLIT),
OPT1("fall", DEBUG_PERF),
OPT1("perf", DEBUG_PERF),
OPT1("perfmon", DEBUG_PERFMON),
OPT1("bat", DEBUG_BATCH),
OPT1("buf", DEBUG_BUFMGR),
OPT1("fs", DEBUG_WM),
OPT1("gs", DEBUG_GS),
OPT1("sync", DEBUG_SYNC),
OPT1("sf", DEBUG_SF),
OPT1("submit", DEBUG_SUBMIT),
OPT1("wm", DEBUG_WM),
OPT1("urb", DEBUG_URB),
OPT1("vs", DEBUG_VS),
OPT1("clip", DEBUG_CLIP),
OPT1("no16", DEBUG_NO16),
OPT1("blorp", DEBUG_BLORP),
OPT1("nodualobj", DEBUG_NO_DUAL_OBJECT_GS),
OPT1("optimizer", DEBUG_OPTIMIZER),
OPT1("mda", DEBUG_MDA),
OPT1("ann", DEBUG_ANNOTATION),
OPT1("no8", DEBUG_NO8),
OPT1("no-oaconfig", DEBUG_NO_OACONFIG),
OPT1("no-fill-opt", DEBUG_NO_FILL_OPT),
OPT1("spill_fs", DEBUG_SPILL_FS),
OPT1("spill_vec4", DEBUG_SPILL_VEC4),
OPT1("cs", DEBUG_CS),
OPT1("hex", DEBUG_HEX),
OPT1("nocompact", DEBUG_NO_COMPACTION),
OPT1("hs", DEBUG_TCS),
OPT1("tcs", DEBUG_TCS),
OPT1("ds", DEBUG_TES),
OPT1("tes", DEBUG_TES),
OPT1("l3", DEBUG_L3),
OPT1("do32", DEBUG_DO32),
OPT1("norbc", DEBUG_NO_CCS),
OPT1("noccs", DEBUG_NO_CCS),
OPT1("noccs-modifier", DEBUG_NO_CCS_MODIFIER),
OPT1("nohiz", DEBUG_NO_HIZ),
OPT1("color", DEBUG_COLOR),
OPT1("reemit", DEBUG_REEMIT),
OPT1("soft64", DEBUG_SOFT64),
OPT1("bt", DEBUG_BT),
OPT1("pc", DEBUG_PIPE_CONTROL),
OPT1("nofc", DEBUG_NO_FAST_CLEAR),
OPT1("no32", DEBUG_NO32),
OPT2("shaders", DEBUG_VS, DEBUG_RT),
OPT1("rt", DEBUG_RT),
OPT1("rt_notrace", DEBUG_RT_NO_TRACE),
OPT1("bvh_blas", DEBUG_BVH_BLAS),
OPT1("bvh_tlas", DEBUG_BVH_TLAS),
OPT1("bvh_blas_ir_hdr", DEBUG_BVH_BLAS_IR_HDR),
OPT1("bvh_tlas_ir_hdr", DEBUG_BVH_TLAS_IR_HDR),
OPT1("bvh_blas_ir_as", DEBUG_BVH_BLAS_IR_AS),
OPT1("bvh_tlas_ir_as", DEBUG_BVH_TLAS_IR_AS),
OPT1("bvh_no_build", DEBUG_BVH_NO_BUILD),
OPT1("task", DEBUG_TASK),
OPT1("mesh", DEBUG_MESH),
OPT1("stall", DEBUG_STALL),
OPT1("no-resource-barrier", DEBUG_NO_RESOURCE_BARRIER),
OPT1("capture-all", DEBUG_CAPTURE_ALL),
OPT1("perf-symbol-names", DEBUG_PERF_SYMBOL_NAMES),
OPT1("swsb-stall", DEBUG_SWSB_STALL),
OPT1("heaps", DEBUG_HEAPS),
OPT1("isl", DEBUG_ISL),
OPT1("sparse", DEBUG_SPARSE),
OPT1("draw_bkp", DEBUG_DRAW_BKP),
OPT1("dispatch_bkp", DEBUG_DISPATCH_BKP),
OPT1("bat-stats", DEBUG_BATCH_STATS),
OPT1("reg-pressure", DEBUG_REG_PRESSURE),
OPT1("shader-print", DEBUG_SHADER_PRINT),
OPT1("cl-quiet", DEBUG_CL_QUIET),
OPT1("no-send-gather", DEBUG_NO_SEND_GATHER),
OPT1("no-vrt", DEBUG_NO_VRT),
OPT1("shaders-lineno", DEBUG_SHADERS_LINENO),
{ NULL, }
#undef OPT1
#undef OPT2
};
uint64_t intel_simd = 0;
static const struct debug_control simd_control[] = {
{ "fs8", DEBUG_FS_SIMD8 },
{ "fs16", DEBUG_FS_SIMD16 },
{ "fs32", DEBUG_FS_SIMD32 },
{ "fs2x8", DEBUG_FS_SIMD2X8 },
{ "fs4x8", DEBUG_FS_SIMD4X8 },
{ "fs2x16", DEBUG_FS_SIMD2X16 },
{ "cs8", DEBUG_CS_SIMD8 },
{ "cs16", DEBUG_CS_SIMD16 },
{ "cs32", DEBUG_CS_SIMD32 },
{ "ts8", DEBUG_TS_SIMD8 },
{ "ts16", DEBUG_TS_SIMD16 },
{ "ts32", DEBUG_TS_SIMD32 },
{ "ms8", DEBUG_MS_SIMD8 },
{ "ms16", DEBUG_MS_SIMD16 },
{ "ms32", DEBUG_MS_SIMD32 },
{ "rt8", DEBUG_RT_SIMD8 },
{ "rt16", DEBUG_RT_SIMD16 },
{ "rt32", DEBUG_RT_SIMD32 },
{ NULL, 0 }
};
uint64_t
intel_debug_flag_for_shader_stage(mesa_shader_stage stage)
{
uint64_t flags[] = {
[MESA_SHADER_VERTEX] = DEBUG_VS,
[MESA_SHADER_TESS_CTRL] = DEBUG_TCS,
[MESA_SHADER_TESS_EVAL] = DEBUG_TES,
[MESA_SHADER_GEOMETRY] = DEBUG_GS,
[MESA_SHADER_FRAGMENT] = DEBUG_WM,
[MESA_SHADER_COMPUTE] = DEBUG_CS,
[MESA_SHADER_KERNEL] = DEBUG_CS,
[MESA_SHADER_TASK] = DEBUG_TASK,
[MESA_SHADER_MESH] = DEBUG_MESH,
[MESA_SHADER_RAYGEN] = DEBUG_RT,
[MESA_SHADER_ANY_HIT] = DEBUG_RT,
[MESA_SHADER_CLOSEST_HIT] = DEBUG_RT,
[MESA_SHADER_MISS] = DEBUG_RT,
[MESA_SHADER_INTERSECTION] = DEBUG_RT,
[MESA_SHADER_CALLABLE] = DEBUG_RT,
};
return flags[stage];
}
#define DEBUG_FS_SIMD (DEBUG_FS_SIMD8 | DEBUG_FS_SIMD16 | \
DEBUG_FS_SIMD32)
#define DEBUG_CS_SIMD (DEBUG_CS_SIMD8 | DEBUG_CS_SIMD16 | DEBUG_CS_SIMD32)
#define DEBUG_TS_SIMD (DEBUG_TS_SIMD8 | DEBUG_TS_SIMD16 | DEBUG_TS_SIMD32)
#define DEBUG_MS_SIMD (DEBUG_MS_SIMD8 | DEBUG_MS_SIMD16 | DEBUG_MS_SIMD32)
#define DEBUG_RT_SIMD (DEBUG_RT_SIMD8 | DEBUG_RT_SIMD16 | DEBUG_RT_SIMD32)
#define DEBUG_SIMD8_ALL \
(DEBUG_FS_SIMD8 | \
DEBUG_CS_SIMD8 | \
DEBUG_TS_SIMD8 | \
DEBUG_MS_SIMD8 | \
DEBUG_RT_SIMD8)
#define DEBUG_SIMD16_ALL \
(DEBUG_FS_SIMD16 | \
DEBUG_CS_SIMD16 | \
DEBUG_TS_SIMD16 | \
DEBUG_MS_SIMD16 | \
DEBUG_RT_SIMD16)
#define DEBUG_SIMD32_ALL \
(DEBUG_FS_SIMD32 | \
DEBUG_CS_SIMD32 | \
DEBUG_TS_SIMD32 | \
DEBUG_MS_SIMD32 | \
DEBUG_RT_SIMD32)
uint64_t intel_debug_batch_frame_start = 0;
uint64_t intel_debug_batch_frame_stop = -1;
uint32_t intel_debug_bkp_before_draw_count = 0;
uint32_t intel_debug_bkp_after_draw_count = 0;
uint64_t intel_shader_dump_filter = 0;
uint32_t intel_debug_bkp_before_dispatch_count = 0;
uint32_t intel_debug_bkp_after_dispatch_count = 0;
static void
parse_debug_bitset(const char *env, const struct debug_control_bitset *tbl)
{
/* Check if env is NULL or empty */
if (!env || !*env)
return;
char *copy = strdup(env);
if (!copy)
return;
/* Tokenize the string by space or comma */
for (char *tok = strtok(copy, ", "); tok; tok = strtok(NULL, ", ")) {
/* Check for negation prefix, useful if user would like to disable certian flags */
bool negate = (*tok == '~' || *tok == '-');
if (negate)
tok++;
for (unsigned i = 0; tbl[i].string; i++) {
if (strcasecmp(tok, tbl[i].string) != 0)
continue;
for (unsigned bit = tbl[i].range[0]; bit <= tbl[i].range[1]; bit++) {
if (negate)
BITSET_CLEAR(intel_debug, bit);
else
BITSET_SET(intel_debug, bit);
}
break;
}
}
free(copy);
}
static void
process_intel_debug_variable_once(void)
{
BITSET_ZERO(intel_debug);
parse_debug_bitset(os_get_option("INTEL_DEBUG"), debug_control);
intel_simd = parse_debug_string(os_get_option("INTEL_SIMD_DEBUG"), simd_control);
intel_debug_batch_frame_start =
debug_get_num_option("INTEL_DEBUG_BATCH_FRAME_START", 0);
intel_debug_batch_frame_stop =
debug_get_num_option("INTEL_DEBUG_BATCH_FRAME_STOP", -1);
intel_debug_bkp_before_draw_count =
debug_get_num_option("INTEL_DEBUG_BKP_BEFORE_DRAW_COUNT", 0);
intel_debug_bkp_after_draw_count =
debug_get_num_option("INTEL_DEBUG_BKP_AFTER_DRAW_COUNT", 0);
intel_shader_dump_filter =
debug_get_num_option("INTEL_SHADER_DUMP_FILTER", 0);
intel_debug_bkp_before_dispatch_count =
debug_get_num_option("INTEL_DEBUG_BKP_BEFORE_DISPATCH_COUNT", 0);
intel_debug_bkp_after_dispatch_count =
debug_get_num_option("INTEL_DEBUG_BKP_AFTER_DISPATCH_COUNT", 0);
if (!(intel_simd & DEBUG_FS_SIMD))
intel_simd |= DEBUG_FS_SIMD;
if (!(intel_simd & DEBUG_CS_SIMD))
intel_simd |= DEBUG_CS_SIMD;
if (!(intel_simd & DEBUG_TS_SIMD))
intel_simd |= DEBUG_TS_SIMD;
if (!(intel_simd & DEBUG_MS_SIMD))
intel_simd |= DEBUG_MS_SIMD;
if (!(intel_simd & DEBUG_RT_SIMD))
intel_simd |= DEBUG_RT_SIMD;
if (BITSET_TEST(intel_debug, DEBUG_NO8))
intel_simd &= ~DEBUG_SIMD8_ALL;
if (BITSET_TEST(intel_debug, DEBUG_NO16))
intel_simd &= ~DEBUG_SIMD16_ALL;
if (BITSET_TEST(intel_debug, DEBUG_NO32))
intel_simd &= ~DEBUG_SIMD32_ALL;
BITSET_CLEAR(intel_debug, DEBUG_NO8);
BITSET_CLEAR(intel_debug, DEBUG_NO16);
BITSET_CLEAR(intel_debug, DEBUG_NO32);
}
static const struct debug_named_value use_jay_options[] = {
{ "vs", BITFIELD_BIT(MESA_SHADER_VERTEX), "Use jay for vertex shaders" },
{ "tes", BITFIELD_BIT(MESA_SHADER_TESS_EVAL), "Use jay for tessellation evaluation shaders" },
{ "fs", BITFIELD_BIT(MESA_SHADER_FRAGMENT), "Use jay for fragment shaders" },
{ "cs", BITFIELD_BIT(MESA_SHADER_COMPUTE), "Use jay for compute shaders" },
{ "all", BITFIELD_BIT(MESA_SHADER_VERTEX) |
BITFIELD_BIT(MESA_SHADER_TESS_EVAL) |
BITFIELD_BIT(MESA_SHADER_FRAGMENT) |
BITFIELD_BIT(MESA_SHADER_COMPUTE), "Use jay for supported shader stages" },
DEBUG_NAMED_VALUE_END
};
DEBUG_GET_ONCE_FLAGS_OPTION(use_jay, "INTEL_JAY", use_jay_options, 0);
static int use_jay = 0;
bool
intel_use_jay(const struct intel_device_info *devinfo, mesa_shader_stage stage)
{
if (stage == MESA_SHADER_KERNEL)
stage = MESA_SHADER_COMPUTE;
return devinfo->ver == 20 && (use_jay & BITFIELD_BIT(stage));
}
bool
intel_use_jay_any_stage(const struct intel_device_info *devinfo)
{
return devinfo->ver == 20 && use_jay;
}
void
process_intel_debug_variable(void)
{
static once_flag process_intel_debug_variable_flag = ONCE_FLAG_INIT;
call_once(&process_intel_debug_variable_flag,
process_intel_debug_variable_once);
use_jay = debug_get_option_use_jay();
}
+203
View File
@@ -0,0 +1,203 @@
/*
* Copyright 2003 VMware, Inc.
* Copyright © 2007 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
*/
#ifndef INTEL_DEBUG_H
#define INTEL_DEBUG_H
#include <stdint.h>
#include "compiler/shader_enums.h"
#include "util/bitset.h"
#include "util/macros.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \file intel_debug.h
*
* Basic INTEL_DEBUG environment variable handling. This file defines the
* list of debugging flags, as well as some macros for handling them.
*/
enum intel_debug_flag {
DEBUG_TEXTURE = 0,
DEBUG_BLIT,
DEBUG_PERF,
DEBUG_PERFMON,
DEBUG_BATCH,
DEBUG_BUFMGR,
DEBUG_SYNC,
DEBUG_SF,
DEBUG_SUBMIT,
DEBUG_URB,
DEBUG_CLIP,
DEBUG_STALL,
DEBUG_NO_RESOURCE_BARRIER,
DEBUG_BLORP,
DEBUG_NO_DUAL_OBJECT_GS,
DEBUG_OPTIMIZER,
DEBUG_MDA,
DEBUG_ANNOTATION,
DEBUG_NO_OACONFIG,
DEBUG_NO_FILL_OPT,
DEBUG_SPILL_FS,
DEBUG_SPILL_VEC4,
DEBUG_HEX,
DEBUG_NO_COMPACTION,
DEBUG_L3,
DEBUG_NO_CCS,
DEBUG_NO_HIZ,
DEBUG_NO_CCS_MODIFIER,
DEBUG_COLOR,
DEBUG_REEMIT,
DEBUG_SOFT64,
DEBUG_BT,
DEBUG_PIPE_CONTROL,
DEBUG_NO_FAST_CLEAR,
DEBUG_CAPTURE_ALL,
DEBUG_PERF_SYMBOL_NAMES,
DEBUG_SWSB_STALL,
DEBUG_HEAPS,
DEBUG_ISL,
DEBUG_SPARSE,
DEBUG_DRAW_BKP,
DEBUG_DISPATCH_BKP,
DEBUG_BATCH_STATS,
DEBUG_REG_PRESSURE,
DEBUG_SHADER_PRINT,
DEBUG_CL_QUIET,
DEBUG_BVH_BLAS,
DEBUG_BVH_TLAS,
DEBUG_BVH_BLAS_IR_HDR,
DEBUG_BVH_TLAS_IR_HDR,
DEBUG_BVH_BLAS_IR_AS,
DEBUG_BVH_TLAS_IR_AS,
DEBUG_BVH_NO_BUILD,
DEBUG_NO_SEND_GATHER,
DEBUG_NO_VRT,
DEBUG_RT_NO_TRACE,
DEBUG_SHADERS_LINENO,
/* Keep the stages grouped */
DEBUG_VS,
DEBUG_TCS,
DEBUG_TES,
DEBUG_GS,
DEBUG_WM,
DEBUG_TASK,
DEBUG_MESH,
DEBUG_CS,
DEBUG_RT,
DEBUG_NO8,
DEBUG_NO16,
DEBUG_NO32,
DEBUG_DO32,
/* Must be the last entry */
INTEL_DEBUG_MAX,
};
extern BITSET_WORD intel_debug[BITSET_WORDS(INTEL_DEBUG_MAX)];
/* Check if a debug flag is enabled by testing its bit position */
#define INTEL_DEBUG(flag) unlikely(BITSET_TEST(intel_debug, (flag)))
/* These flags are not compatible with the disk shader cache */
#define DEBUG_DISK_CACHE_DISABLE_MASK 0
/* Flags to determine what bvh to dump out */
#define INTEL_DEBUG_BVH_ANY (unlikely(INTEL_DEBUG(DEBUG_BVH_BLAS) || \
INTEL_DEBUG(DEBUG_BVH_TLAS) || \
INTEL_DEBUG(DEBUG_BVH_BLAS_IR_HDR) || \
INTEL_DEBUG(DEBUG_BVH_TLAS_IR_HDR) || \
INTEL_DEBUG(DEBUG_BVH_BLAS_IR_AS) || \
INTEL_DEBUG(DEBUG_BVH_TLAS_IR_AS)))
extern uint64_t intel_simd;
extern uint32_t intel_debug_bkp_before_draw_count;
extern uint32_t intel_debug_bkp_after_draw_count;
extern uint32_t intel_debug_bkp_before_dispatch_count;
extern uint32_t intel_debug_bkp_after_dispatch_count;
extern uint64_t intel_debug_batch_frame_start;
extern uint64_t intel_debug_batch_frame_stop;
extern uint64_t intel_shader_dump_filter;
#define INTEL_SIMD(type, size) (!!(intel_simd & (DEBUG_ ## type ## _SIMD ## size)))
/* VS, TCS, TES and GS stages are dispatched in one size */
#define DEBUG_FS_SIMD8 (1ull << 0)
#define DEBUG_FS_SIMD16 (1ull << 1)
#define DEBUG_FS_SIMD32 (1ull << 2)
#define DEBUG_FS_SIMD2X8 (1ull << 3)
#define DEBUG_FS_SIMD4X8 (1ull << 4)
#define DEBUG_FS_SIMD2X16 (1ull << 5)
#define DEBUG_CS_SIMD8 (1ull << 6)
#define DEBUG_CS_SIMD16 (1ull << 7)
#define DEBUG_CS_SIMD32 (1ull << 8)
#define DEBUG_TS_SIMD8 (1ull << 9)
#define DEBUG_TS_SIMD16 (1ull << 10)
#define DEBUG_TS_SIMD32 (1ull << 11)
#define DEBUG_MS_SIMD8 (1ull << 12)
#define DEBUG_MS_SIMD16 (1ull << 13)
#define DEBUG_MS_SIMD32 (1ull << 14)
#define DEBUG_RT_SIMD8 (1ull << 15)
#define DEBUG_RT_SIMD16 (1ull << 16)
#define DEBUG_RT_SIMD32 (1ull << 17)
#define SIMD_DISK_CACHE_MASK ((1ull << 18) - 1)
#ifdef HAVE_ANDROID_PLATFORM
#define LOG_TAG "INTEL-MESA"
#include <android/log.h>
#define dbg_printf(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#else
#define dbg_printf(...) fprintf(stderr, __VA_ARGS__)
#endif /* HAVE_ANDROID_PLATFORM */
#define DBG(...) do { \
if (INTEL_DEBUG(FILE_DEBUG_FLAG)) \
dbg_printf(__VA_ARGS__); \
} while(0)
extern uint64_t intel_debug_flag_for_shader_stage(mesa_shader_stage stage);
struct intel_device_info;
struct nir_shader;
extern bool intel_use_jay(const struct intel_device_info *devinfo,
mesa_shader_stage stage);
extern bool intel_use_jay_any_stage(const struct intel_device_info *devinfo);
extern void process_intel_debug_variable(void);
#ifdef __cplusplus
}
#endif
#endif /* INTEL_DEBUG_H */
File diff suppressed because it is too large. Load diff
+267
View File
@@ -0,0 +1,267 @@
/*
* Copyright © 2013 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.
*
*/
#ifndef INTEL_DEVICE_INFO_H
#define INTEL_DEVICE_INFO_H
#include <stdbool.h>
#include <stdint.h>
#include "util/bitset.h"
#include "util/macros.h"
#include "compiler/shader_enums.h"
#include "intel_debug.h"
#include "intel_kmd.h"
#include "intel/dev/intel_wa.h"
#include "intel/dev/intel_device_info_gen.h"
#ifdef __cplusplus
extern "C" {
#endif
#define intel_platform_in_range(platform, platform_range) \
(((platform) >= INTEL_PLATFORM_ ## platform_range ## _START) && \
((platform) <= INTEL_PLATFORM_ ## platform_range ## _END))
#define intel_device_info_is_atsm(devinfo) \
intel_platform_in_range((devinfo)->platform, ATSM)
#define intel_device_info_is_dg2(devinfo) \
(intel_platform_in_range((devinfo)->platform, DG2) || \
intel_platform_in_range((devinfo)->platform, ATSM))
#define intel_device_info_is_mtl(devinfo) \
intel_platform_in_range((devinfo)->platform, MTL)
#define intel_device_info_is_arl(devinfo) \
intel_platform_in_range((devinfo)->platform, ARL)
#define intel_device_info_is_mtl_or_arl(devinfo) \
(intel_device_info_is_mtl(devinfo) || intel_device_info_is_arl(devinfo))
#define PAT_ENTRY(index_, mmap_) \
{ \
.index = index_, \
.mmap = INTEL_DEVICE_INFO_MMAP_MODE_##mmap_ \
}
#ifdef GFX_VER
#define intel_device_info_is_9lp(devinfo) \
(GFX_VER == 9 && ((devinfo)->platform == INTEL_PLATFORM_BXT || \
(devinfo)->platform == INTEL_PLATFORM_GLK))
#else
#define intel_device_info_is_9lp(devinfo) \
((devinfo)->platform == INTEL_PLATFORM_BXT || \
(devinfo)->platform == INTEL_PLATFORM_GLK)
#endif
#define GFX_IP_VER(major, minor) ((major << 16) | minor)
#define BMG_G31_IP_VER GFX_IP_VER(20, 2)
#define intel_device_info_is_bmg_g31(devinfo) (devinfo->gfx_ip_ver == BMG_G31_IP_VER)
static inline bool
intel_device_info_slice_available(const struct intel_device_info *devinfo,
int slice)
{
assert(slice < INTEL_DEVICE_MAX_SLICES);
return (devinfo->slice_masks & (1U << slice)) != 0;
}
static inline bool
intel_device_info_subslice_available(const struct intel_device_info *devinfo,
int slice, int subslice)
{
return (devinfo->subslice_masks[slice * devinfo->subslice_slice_stride +
subslice / 8] & (1U << (subslice % 8))) != 0;
}
static inline bool
intel_device_info_eu_available(const struct intel_device_info *devinfo,
int slice, int subslice, int eu)
{
unsigned subslice_offset = slice * devinfo->eu_slice_stride +
subslice * devinfo->eu_subslice_stride;
return (devinfo->eu_masks[subslice_offset + eu / 8] & (1U << eu % 8)) != 0;
}
static inline uint32_t
intel_device_info_subslice_total(const struct intel_device_info *devinfo)
{
uint32_t total = 0;
for (size_t i = 0; i < ARRAY_SIZE(devinfo->subslice_masks); i++) {
total += __builtin_popcount(devinfo->subslice_masks[i]);
}
return total;
}
static inline uint32_t
intel_device_info_eu_total(const struct intel_device_info *devinfo)
{
uint32_t total = 0;
for (size_t i = 0; i < ARRAY_SIZE(devinfo->eu_masks); i++)
total += __builtin_popcount(devinfo->eu_masks[i]);
return total;
}
/**
* Computes the bound of dualsubslice ID that can be used on this device.
*
* You should use this number if you're going to make calculation based on the
* slice/dualsubslice ID provided by the SR0.0 EU register. The maximum
* dualsubslice ID can be superior to the total number of dualsubslices on the
* device, depending on fusing.
*
* On a 16 dualsubslice GPU, the maximum dualsubslice ID is 15. This function
* would return the exclusive bound : 16.
*/
static inline unsigned
intel_device_info_dual_subslice_id_bound(const struct intel_device_info *devinfo)
{
/* Start from the last slice/subslice so we find the answer faster. */
for (int s = devinfo->max_slices - 1; s >= 0; s--) {
for (int ss = devinfo->max_subslices_per_slice - 1; ss >= 0; ss--) {
if (intel_device_info_subslice_available(devinfo, s, ss))
return s * devinfo->max_subslices_per_slice + ss + 1;
}
}
UNREACHABLE("Invalid topology");
return 0;
}
int intel_device_name_to_pci_device_id(const char *name);
const char *intel_platform_name_by_index(unsigned idx);
static inline uint64_t
intel_device_info_timebase_scale(const struct intel_device_info *devinfo,
uint64_t gpu_timestamp)
{
/* Try to avoid going over the 64bits when doing the scaling */
uint64_t upper_ts = gpu_timestamp >> 32;
uint64_t lower_ts = gpu_timestamp & 0xffffffff;
uint64_t upper_num = upper_ts * 1000000000ull;
uint64_t upper_scaled_ts = upper_num / devinfo->timestamp_frequency;
uint64_t upper_remainder = upper_num % devinfo->timestamp_frequency;
uint64_t lower_scaled_ts = ((upper_remainder << 32) + lower_ts * 1000000000ull) /
devinfo->timestamp_frequency;
return (upper_scaled_ts << 32) + lower_scaled_ts;
}
static inline bool
intel_vram_all_mappable(const struct intel_device_info *devinfo)
{
return devinfo->mem.vram.unmappable.size == 0;
}
bool intel_get_device_info_from_fd(int fh, struct intel_device_info *devinfo, int min_ver, int max_ver);
bool intel_get_device_info_from_pci_id(int pci_id,
struct intel_device_info *devinfo);
bool intel_get_device_info_for_build(int pci_id,
struct intel_device_info *devinfo);
/* Only updates intel_device_info::regions::...::free fields. The
* class/instance/size should remain the same over time.
*/
bool intel_device_info_update_memory_info(struct intel_device_info *devinfo,
int fd);
void intel_device_info_topology_reset_masks(struct intel_device_info *devinfo);
void intel_device_info_topology_update_counts(struct intel_device_info *devinfo);
void intel_device_info_update_pixel_pipes(struct intel_device_info *devinfo, uint8_t *subslice_masks);
void intel_device_info_update_l3_banks(struct intel_device_info *devinfo);
uint32_t intel_device_info_get_eu_count_first_subslice(const struct intel_device_info *devinfo);
void intel_device_info_update_cs_workgroup_threads(struct intel_device_info *devinfo);
bool intel_device_info_compute_system_memory(struct intel_device_info *devinfo, bool update);
#ifdef GFX_VERx10
#define intel_needs_workaround(devinfo, id) \
(INTEL_WA_ ## id ## _GFX_VER && \
BITSET_TEST((devinfo)->workarounds, INTEL_WA_##id))
#else
#define intel_needs_workaround(devinfo, id) \
BITSET_TEST((devinfo)->workarounds, INTEL_WA_##id)
#endif
enum intel_wa_steppings intel_device_info_wa_stepping(struct intel_device_info *devinfo);
uint32_t intel_device_info_get_max_slm_size(const struct intel_device_info *devinfo);
uint32_t intel_device_info_get_max_preferred_slm_size(const struct intel_device_info *devinfo);
static inline unsigned
intel_device_info_get_max_engine_prefetch(const struct intel_device_info *devinfo)
{
unsigned max_prefetch = 0;
for (unsigned engine = INTEL_ENGINE_CLASS_RENDER;
engine < ARRAY_SIZE(devinfo->engine_class_prefetch); engine++)
max_prefetch = MAX2(max_prefetch, devinfo->engine_class_prefetch[engine]);
return max_prefetch;
}
/**
* True if this device supports the Extended Bindless Surface Offset mode,
* which offers 26-bit surface handles, instead of 20-bit. This effectively
* gives us 4GB of bindless surface descriptors instead of only 64MB.
*
* On Gfx12.5 this is enabled via an "ExBSO" bit in the SEND instruction.
*/
static inline bool
intel_has_extended_bindless(const struct intel_device_info *devinfo)
{
return devinfo->verx10 >= 125;
}
/**
* Whether indirect UBO loads should use the sampler or go through the
* data/constant cache. For the sampler, UBO surface states have to be set
* up with VK_FORMAT_R32G32B32A32_FLOAT whereas if it's going through the
* constant or data cache, UBOs must use VK_FORMAT_RAW.
*/
static inline bool
intel_indirect_ubos_use_sampler(const struct intel_device_info *devinfo)
{
return devinfo->ver < 12;
}
static inline bool
intel_use_tcs_multi_patch(const struct intel_device_info *devinfo)
{
return devinfo->ver >= 12;
}
#ifdef __cplusplus
}
#endif
#endif /* INTEL_DEVICE_INFO_H */
+461
View File
@@ -0,0 +1,461 @@
# Copyright © 2024 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.
from textwrap import dedent
# TYPES is an ordered list of all declarations in this file.
TYPES = []
# TYPES_BY_NAME allows the lookup of any declaration
TYPES_BY_NAME = {}
class Define:
"""Specifies a c macro definition."""
def __init__(self, name, value, comment=None):
self.name = name
self.value = value
self.comment = comment
TYPES.append(self)
class EnumValue:
"""allows comments and setting of enum values"""
def __init__(self, name, value=None, comment=None,
group_begin=None, group_end=None):
self.name = name
self.value = value
self.comment = comment
self.group_begin = group_begin
self.group_end = group_end
def __str__(self):
return self.name
class Enum:
"""Stores details needed to declare and serialize an enumeration"""
def __init__(self, name, values, external=False):
self.name = name
self.values = []
for v in values:
if isinstance(v, EnumValue):
self.values.append(v)
else:
self.values.append(EnumValue(v))
self.external = external
TYPES.append(self)
TYPES_BY_NAME[name] = TYPES[-1]
class Member:
"""Stores details needed to declare and serialize the member of a struct."""
def __init__(self, member_type, name, array=None,
compiler_field=False, ray_tracing_field=False,
comment=None):
self.member_type = member_type
self.name = name
self.array = array
# indicates whether this field is used by the compiler, and whether it
# should be included in the shader compiler cache hash function.
self.compiler_field = compiler_field
self.ray_tracing_field = ray_tracing_field
self.comment=comment
class Struct:
"""Stores details needed to declare and serialize a struct"""
def __init__(self, name, members):
self.name = name
self.members = members
TYPES.append(self)
TYPES_BY_NAME[name] = TYPES[-1]
INT_TYPES = set(["uint8_t",
"uint16_t",
"uint32_t",
"uint64_t",
"unsigned",
"int"])
FUNDAMENTAL_TYPES = set(["char", "bool"]).union(INT_TYPES)
Define("INTEL_DEVICE_MAX_NAME_SIZE", 64)
Define("INTEL_DEVICE_MAX_SLICES", 8)
Define("INTEL_DEVICE_MAX_SUBSLICES", 8, "Maximum on gfx11")
Define("INTEL_DEVICE_MAX_EUS_PER_SUBSLICE", 16, "Maximum on gfx11")
Define("INTEL_DEVICE_MAX_PIXEL_PIPES", 16, "Maximum on DG2")
Enum("intel_platform",
[EnumValue("INTEL_PLATFORM_GFX3", value=1),
"INTEL_PLATFORM_I965",
"INTEL_PLATFORM_ILK",
"INTEL_PLATFORM_G4X",
"INTEL_PLATFORM_SNB",
"INTEL_PLATFORM_IVB",
"INTEL_PLATFORM_BYT",
"INTEL_PLATFORM_HSW",
"INTEL_PLATFORM_BDW",
"INTEL_PLATFORM_CHV",
"INTEL_PLATFORM_SKL",
"INTEL_PLATFORM_BXT",
"INTEL_PLATFORM_KBL",
"INTEL_PLATFORM_GLK",
"INTEL_PLATFORM_CFL",
"INTEL_PLATFORM_ICL",
"INTEL_PLATFORM_EHL",
"INTEL_PLATFORM_TGL",
"INTEL_PLATFORM_RKL",
"INTEL_PLATFORM_DG1",
"INTEL_PLATFORM_ADL",
"INTEL_PLATFORM_RPL",
EnumValue("INTEL_PLATFORM_DG2_G10", group_begin="DG2"),
"INTEL_PLATFORM_DG2_G11",
EnumValue("INTEL_PLATFORM_DG2_G12", group_end="DG2"),
EnumValue("INTEL_PLATFORM_ATSM_G10", group_begin="ATSM"),
EnumValue("INTEL_PLATFORM_ATSM_G11", group_end="ATSM"),
EnumValue("INTEL_PLATFORM_MTL_U", group_begin="MTL"),
EnumValue("INTEL_PLATFORM_MTL_H", group_end="MTL"),
EnumValue("INTEL_PLATFORM_ARL_U", group_begin="ARL"),
EnumValue("INTEL_PLATFORM_ARL_H", group_end="ARL"),
"INTEL_PLATFORM_LNL",
"INTEL_PLATFORM_BMG",
"INTEL_PLATFORM_PTL",
"INTEL_PLATFORM_WCL",
"INTEL_PLATFORM_NVL_U",
"INTEL_PLATFORM_NVL_P",
])
Struct("intel_memory_class_instance",
[ Member("int", "klass",
comment = "Kernel backend specific class value, no translation needed yet"),
Member("int", "instance")])
Enum("intel_device_info_mmap_mode",
[EnumValue("INTEL_DEVICE_INFO_MMAP_MODE_INVALID",
comment=dedent("""No CPU access allowed.""")),
EnumValue("INTEL_DEVICE_INFO_MMAP_MODE_WC"),
EnumValue("INTEL_DEVICE_INFO_MMAP_MODE_WB")
])
Struct("intel_device_info_pat_entry",
[Member("uint8_t", "index"),
Member("intel_device_info_mmap_mode", "mmap",
comment=dedent("""\
This tells KMD what caching mode the CPU mapping should use.
It has nothing to do with any PAT cache modes."""))])
Enum("intel_engine_class",
["INTEL_ENGINE_CLASS_RENDER",
"INTEL_ENGINE_CLASS_COPY",
"INTEL_ENGINE_CLASS_VIDEO",
"INTEL_ENGINE_CLASS_VIDEO_ENHANCE",
"INTEL_ENGINE_CLASS_COMPUTE",
"INTEL_ENGINE_CLASS_INVALID"])
Enum("intel_kmd_type",
["INTEL_KMD_TYPE_INVALID",
"INTEL_KMD_TYPE_I915",
"INTEL_KMD_TYPE_XE",
"INTEL_KMD_TYPE_STUB",
"INTEL_KMD_TYPE_LAST"
], external=True)
Struct("intel_device_info_mem_region",
[Member("uint64_t", "size"),
Member("uint64_t", "free")])
Struct("intel_device_info_ram_desc",
[Member("intel_memory_class_instance", "mem"),
Member("intel_device_info_mem_region", "mappable"),
Member("intel_device_info_mem_region", "unmappable")])
Struct("intel_device_info_mem_desc",
[Member("bool", "use_class_instance"),
Member("intel_device_info_ram_desc", "sram"),
Member("intel_device_info_ram_desc", "vram")])
Struct("intel_device_info_urb_desc",
[Member("int", "size"),
Member("int", "min_entries", array=8),
Member("int", "max_entries", array=8)])
Struct("intel_device_info_pat_desc",
[Member("intel_device_info_pat_entry", "cached_coherent",
comment="To be used when CPU access is frequent, WB + 1 or 2 way coherent"),
Member("intel_device_info_pat_entry", "scanout",
comment="scanout and external BOs"),
Member("intel_device_info_pat_entry", "compressed_scanout",
comment="Only supported in Xe2, compressed + WC for displayable resources"),
Member("intel_device_info_pat_entry", "compressed",
comment="Only supported in Xe2, compressed + WC for non-displayable resources"),
Member("intel_device_info_pat_entry", "writeback_incoherent",
comment=("BOs without special needs, can be WB not coherent "
"or WC it depends on the platforms and KMD")),
Member("intel_device_info_pat_entry", "writecombining")])
Struct("intel_device_info",
[Member("intel_kmd_type", "kmd_type"),
Member("int", "ver", compiler_field=True,
comment="Driver internal numbers used to differentiate platforms."),
Member("int", "verx10", compiler_field=True),
Member("uint32_t", "gfx_ip_ver", compiler_field=True,
comment=dedent("""\
This is the run-time hardware GFX IP version that may be more specific
than ver/verx10. ver/verx10 may be more useful for comparing a class
of devices whereas gfx_ip_ver may be more useful for precisely
checking for a graphics ip type. GFX_IP_VER(major, minor) should be
used to compare IP versions.""")),
Member("int", "revision",
comment=dedent("""\
This revision is queried from KMD unlike
pci_revision_id from drm device. Its value is not always
same as the pci_revision_id.
For LNL+ this is the stepping of GT IP/GMD RevId.""")),
Member("int", "gt"),
Member("uint16_t", "pci_domain", comment="PCI info"),
Member("uint8_t", "pci_bus"),
Member("uint8_t", "pci_dev"),
Member("uint8_t", "pci_func"),
Member("uint16_t", "pci_device_id"),
Member("uint8_t", "pci_revision_id"),
Member("intel_platform", "platform", compiler_field=True),
Member("bool", "has_hiz_and_separate_stencil"),
Member("bool", "has_sample_with_hiz"),
Member("bool", "has_bit6_swizzle"),
Member("bool", "has_llc"),
Member("bool", "has_pln", compiler_field=True),
Member("bool", "has_64bit_float", compiler_field=True),
Member("bool", "has_64bit_float_via_math_pipe", compiler_field=True),
Member("bool", "has_64bit_int", compiler_field=True),
Member("bool", "has_bfloat16", compiler_field=True),
Member("bool", "has_fp8", compiler_field=True),
Member("bool", "has_integer_dword_mul", compiler_field=True),
Member("bool", "has_systolic", compiler_field=True),
Member("bool", "supports_simd16_3src", compiler_field=True),
Member("bool", "disable_ccs_repack"),
Member("bool", "has_flat_ccs",
comment=dedent("""\
True if CCS uses a flat virtual address translation to a memory
carve-out, rather than aux map translations, or additional surfaces.""")),
Member("bool", "has_aux_map"),
Member("bool", "has_caching_uapi"),
Member("bool", "has_tiling_uapi"),
Member("bool", "has_ray_tracing", compiler_field=True),
Member("bool", "has_ray_query"),
Member("bool", "has_local_mem"),
Member("bool", "has_lsc", compiler_field=True),
Member("bool", "has_mesh_shading"),
Member("bool", "has_mmap_offset"),
Member("bool", "has_partial_mmap_offset"),
Member("bool", "has_userptr_probe"),
Member("bool", "has_context_isolation"),
Member("bool", "has_set_pat_uapi"),
Member("bool", "has_indirect_unroll"),
Member("bool", "supports_low_latency_hint"),
Member("bool", "xe2_has_no_compression_hint"),
Member("bool", "xe_has_state_cache_perf_fix"),
Member("bool", "has_madvise_purgeable"),
Member("bool", "has_userptr_uapi"),
Member("bool", "has_coarse_pixel_primitive_and_cb", compiler_field=True,
comment=dedent("""\
Whether this platform supports fragment shading rate controlled by a
primitive in geometry shaders and by a control buffer.""")),
Member("bool", "has_compute_engine", comment="Whether this platform has compute engine"),
Member("bool", "needs_null_push_constant_tbimr_workaround",
comment=dedent("""\
Whether the platform needs an undocumented workaround for a hardware bug
that affects draw calls with a pixel shader that has 0 push constant cycles
when TBIMR is enabled, which has been seen to lead to hangs. To avoid the
issue we simply pad the push constant payload to be at least 1 register.""")),
Member("unsigned", "num_slices",
comment=dedent("""\
GPU hardware limits
In general, you can find shader thread maximums by looking at the "Maximum
Number of Threads" field in the Intel PRM description of the 3DSTATE_VS,
3DSTATE_GS, 3DSTATE_HS, 3DSTATE_DS, and 3DSTATE_PS commands. URB entry
limits come from the "Number of URB Entries" field in the
3DSTATE_URB_VS command and friends.
These fields are used to calculate the scratch space to allocate. The
amount of scratch space can be larger without being harmful on modern
GPUs, however, prior to Haswell, programming the maximum number of threads
to greater than the hardware maximum would cause GPU performance to tank.
Total number of slices present on the device whether or not they've been
fused off.
XXX: CS thread counts are limited by the inability to do cross subslice
communication. It is the effectively the number of logical threads which
can be executed in a subslice. Fuse configurations may cause this number
to change, so we program @max_cs_threads as the lower maximum.""")),
Member("unsigned", "max_slices", compiler_field=True,
comment=dedent("""\
Maximum number of slices present on this device (can be more than
num_slices if some slices are fused).""")),
Member("unsigned", "num_subslices", array="INTEL_DEVICE_MAX_SLICES",
comment="Number of subslices for each slice (used to be uniform until CNL)."),
Member("unsigned", "max_subslices_per_slice", compiler_field=True,
comment=dedent("""\
Maximum number of subslices per slice present on this device (can be
more than the maximum value in the num_subslices[] array if some
subslices are fused).
This is GT_SS_PER_SLICE in SKU.""")),
Member("unsigned", "ppipe_subslices", array="INTEL_DEVICE_MAX_PIXEL_PIPES",
comment="Number of subslices on each pixel pipe (ICL)."),
Member("unsigned", "max_eus_per_subslice", compiler_field=True,
comment="Maximum number of EUs per subslice (some EUs can be fused off)."),
Member("unsigned", "num_thread_per_eu", compiler_field=True,
comment="Number of threads per eu, varies between 4 and 8 between generations."),
Member("uint8_t", "grf_size",
comment="Size of a register from the EU GRF file in bytes."),
Member("uint8_t", "slice_masks",
comment="A bit mask of the slices available."),
Member("uint8_t", "subslice_masks",
array="INTEL_DEVICE_MAX_SLICES * DIV_ROUND_UP(INTEL_DEVICE_MAX_SUBSLICES, 8)",
compiler_field=True,
ray_tracing_field=True,
comment=dedent("""\
An array of bit mask of the subslices available, use subslice_slice_stride
to access this array.""")),
Member("unsigned", "subslice_total",
comment=dedent("""\
The number of enabled subslices (considering fusing). For exactly which
subslices are enabled, see subslice_masks[].""")),
Member("uint8_t", "eu_masks",
array=("INTEL_DEVICE_MAX_SLICES * INTEL_DEVICE_MAX_SUBSLICES * "
"DIV_ROUND_UP(INTEL_DEVICE_MAX_EUS_PER_SUBSLICE, 8)"),
comment=dedent("""\
An array of bit mask of EUs available, use eu_slice_stride &
eu_subslice_stride to access this array.""")),
Member("uint16_t", "subslice_slice_stride", compiler_field=True,
comment="Stride to access subslice_masks[]."),
Member("uint16_t", "eu_slice_stride",
comment="Strides to access eu_masks[]."),
Member("uint16_t", "eu_subslice_stride"),
Member("unsigned", "l3_banks"),
Member("unsigned", "max_vs_threads",
comment="Maximum Vertex Shader threads"),
Member("unsigned", "max_tcs_threads",
comment="Maximum Hull Shader threads"),
Member("unsigned", "max_tes_threads",
comment="Maximum Domain Shader threads"),
Member("unsigned", "max_gs_threads",
comment="Maximum Geometry Shader threads"),
Member("unsigned", "max_wm_threads",
comment=dedent("""\
Theoretical maximum number of Pixel Shader threads.
PSD means Pixel Shader Dispatcher. On modern Intel GPUs, hardware will
automatically scale pixel shader thread count, based on a single value
programmed into 3DSTATE_PS.
To calculate the maximum number of threads for Gfx8 beyond (which have
multiple Pixel Shader Dispatchers):
- Look up 3DSTATE_PS and find "Maximum Number of Threads Per PSD"
- Usually there's only one PSD per subslice, so use the number of
subslices for number of PSDs.
- For max_wm_threads, the total should be PSD threads * #PSDs.""")),
Member("unsigned", "max_threads_per_psd"),
Member("unsigned", "max_cs_threads",
comment=dedent("""\
Maximum Compute Shader threads per subslice.
Actual maximum compute shader threads is max_cs_threads * subslices.
Thread count * number of EUs per subslice""")),
Member("unsigned", "num_geom_pipes", comment="Number of geometry pipes"),
Member("unsigned", "num_depth_pipes", comment="Number of depth pipes"),
Member("unsigned", "num_color_pipes", comment="Number of color pipes"),
Member("unsigned", "max_cs_workgroup_threads", compiler_field=True,
comment=dedent("""\
Maximum number of threads per workgroup supported by the GPGPU_WALKER or
COMPUTE_WALKER command.
This may be smaller than max_cs_threads as it takes into account added
restrictions on the GPGPU/COMPUTE_WALKER commands. While max_cs_threads
expresses the total parallelism of the GPU, this expresses the maximum
number of threads we can dispatch in a single workgroup.""")),
Member("unsigned", "max_scratch_ids", array="MESA_SHADER_STAGES", compiler_field=True,
comment=dedent("""\
The maximum number of potential scratch ids. Due to hardware
implementation details, the range of scratch ids may be larger than the
number of subslices.""")),
Member("uint32_t", "max_scratch_size_per_thread", compiler_field=True),
Member("intel_device_info_urb_desc", "urb"),
Member("unsigned", "max_constant_urb_size_kb"),
Member("unsigned", "mesh_max_constant_urb_size_kb"),
Member("unsigned", "engine_class_prefetch", array="INTEL_ENGINE_CLASS_INVALID"),
Member("unsigned", "engine_class_supported_count", array="INTEL_ENGINE_CLASS_INVALID"),
Member("unsigned", "mem_alignment"),
Member("uint64_t", "timestamp_frequency"),
Member("uint64_t", "aperture_bytes"),
Member("uint64_t", "gtt_size"),
Member("int", "simulator_id"),
Member("char", "name", array="INTEL_DEVICE_MAX_NAME_SIZE"),
Member("bool", "no_hw"),
Member("bool", "probe_forced", comment="Device needed INTEL_FORCE_PROBE"),
Member("intel_device_info_mem_desc", "mem"),
Member("intel_device_info_pat_desc", "pat"),
Member("bool", "is_virtio")]
)
+166
View File
@@ -0,0 +1,166 @@
#!/usr/bin/env python3
COPYRIGHT = """\
/*
* Copyright 2024 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, sub license, 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*/
"""
import os
import sys
from textwrap import indent
from mako.template import Template
from mako import exceptions
from intel_device_info import TYPES_BY_NAME, Enum
template = COPYRIGHT + """
/* DO NOT EDIT - This file generated automatically by intel_device_info_gen_h.py script */
#ifndef INTEL_DEVICE_INFO_GEN_H
#define INTEL_DEVICE_INFO_GEN_H
#include <stdbool.h>
#include <stdint.h>
#include "util/macros.h"
#include "compiler/shader_enums.h"
#include "intel/dev/intel_wa.h"
#ifdef __cplusplus
extern "C" {
#endif
<%! import intel_device_info %>
% for decl in intel_device_info.TYPES:
% if isinstance(decl, intel_device_info.Define):
${format_define(decl)}
% elif isinstance(decl, intel_device_info.Enum) and not decl.external:
enum ${decl.name} {
% for value in decl.values:
${format_enum_value(value)}
% endfor
};
% elif isinstance(decl, intel_device_info.Struct):
struct ${decl.name}
{
% for member in decl.members:
${format_struct_member(member)}
% endfor
% if decl.name == "intel_device_info":
BITSET_DECLARE(workarounds, INTEL_WA_NUM);
% endif
};
% endif
% endfor
#ifdef __cplusplus
}
#endif
#endif /* INTEL_DEVICE_INFO_GEN_H */
"""
def format_enum_value(v):
"""
Routine to format the individual lines within an enum declaration.
This is inconvenient to implement with mako. Templates are an
inconvenient tool for conditionally formatting:
- inline comments
- "grouped" values as required by intel_platform
- specific values
"""
comment = ""
if v.comment:
comment = f" /* {v.comment} */"
value = ""
if v.value is not None:
value = f" = {v.value}"
decl = f"{v.name}{value},{comment}"
if v.group_begin:
decl = f"{decl}\nINTEL_PLATFORM_{v.group_begin}_START = {v.name},"
if v.group_end:
decl = f"{decl}\nINTEL_PLATFORM_{v.group_end}_END = {v.name},"
return indent(decl, " ")
def format_define(v):
"""
Routine to format the printing of a macro declaration. Conditional
inline comments are difficult to format in mako.
"""
comment = ""
if v.comment:
comment = f" /* {v.comment} */"
return f"#define {v.name} ({v.value}){comment}"
def format_struct_member(m):
"""
Routine to format the printing of a struct member. Mako templates are not
helpful in formatting the following aspects of intel_device_info structs:
- multiline vs single line comments
- optional array lengths
- enum / struct member type declarations
"""
comment = ""
if m.comment:
if "\n" in m.comment:
comment_lines = [ f" * {line}".rstrip() for line in m.comment.split('\n')]
comment_lines.insert(0, "\n/**")
comment_lines.append(" */\n")
comment = '\n'.join(comment_lines)
else:
comment = f"\n/* {m.comment} */\n"
array = ""
if m.array:
array = f"[{m.array}]"
member_type = m.member_type
if member_type in TYPES_BY_NAME:
if isinstance(TYPES_BY_NAME[member_type], Enum):
member_type = f"enum {member_type}"
else:
member_type = f"struct {member_type}"
return indent(f"{comment}{member_type} {m.name}{array};", " ")
def main():
"""print intel_device_info_gen.h at the specified path"""
if len(sys.argv) > 1:
outf = open(sys.argv[1], 'w', encoding='utf-8')
else:
outf = sys.stdout
try:
outf.write(Template(template).render(format_enum_value=format_enum_value,
format_struct_member=format_struct_member,
format_define=format_define))
except:
# provide some debug information to the user
print(exceptions.text_error_template().render(format_enum_value=format_enum_value,
format_struct_member=format_struct_member,
format_define=format_define))
sys.exit(1)
outf.close()
if __name__ == "__main__":
main()
@@ -0,0 +1,78 @@
/*
* Copyright © 2022 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.
*/
#undef NDEBUG
#include <assert.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "util/libdrm.h"
#include "intel_device_info.h"
#include "intel_device_info_test.h"
int
main(int argc, char *argv[])
{
drmDevicePtr devices[8];
int max_devices;
if (argc != 2) {
fprintf(stderr, "format: %s verx10_number\n", argv[0]);
return -1;
}
int verx10 = atoi(argv[1]);
max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
if (max_devices < 1) {
fprintf(stderr, "Device not found\n");
return -1;
}
for (int i = 0; i < max_devices; i++) {
struct intel_device_info devinfo;
const char *path = devices[i]->nodes[DRM_NODE_RENDER];
int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0)
continue;
bool success = intel_get_device_info_from_fd(fd, &devinfo, -1, -1);
close(fd);
if (!success)
continue;
fprintf(stderr, "%u\n", devinfo.verx10);
assert(devinfo.verx10 == verx10);
verify_device_info(&devinfo);
assert(devinfo.engine_class_prefetch[INTEL_ENGINE_CLASS_RENDER] > 0);
}
return 0;
}
@@ -0,0 +1,43 @@
/*
* Copyright © 2024 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.
*
*/
#ifndef INTEL_DEVICE_INFO_SERIALIZE_H
#define INTEL_DEVICE_INFO_SERIALIZE_H
#include "dev/intel_device_info.h"
#include "util/parson.h"
/* Initialize a device info struct with the json-formatted data at the path.
* Returns false if json format is incompatible (from an older version of
* mesa)
*/
bool intel_device_info_from_json(const char *path,
struct intel_device_info *devinfo);
/* Dump all device info data into a parson tree, for serializaiton. Caller
* must free the returned reference with json_value_free()
*/
JSON_Value *intel_device_info_dump_json(const struct intel_device_info *devinfo);
#endif /* INTEL_DEVICE_INFO_SERIALIZE_H */
+219
View File
@@ -0,0 +1,219 @@
#!/usr/bin/env python3
COPYRIGHT = """\
/*
* Copyright 2024 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, sub license, 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*/
"""
import hashlib
import os
import sys
from mako.template import Template
from mako import exceptions
from intel_device_info import TYPES, TYPES_BY_NAME, FUNDAMENTAL_TYPES, Enum
template = COPYRIGHT + """
/* DO NOT EDIT - This file generated automatically by intel_device_serialize_c.py script */
#include "dev/intel_device_info_serialize.h"
#include "util/parson.h"
<%! import intel_device_info %>
% for decl in TYPES:
% if isinstance(decl, intel_device_info.Enum):
static JSON_Value *
dump_${decl.name}(enum ${decl.name} arg) {
switch (arg) {
% for value in decl.values:
case ${value}:
return json_value_init_string("${value}");
% endfor
default:
UNREACHABLE("invalid ${decl.name} value");
}
}
static enum ${decl.name}
load_${decl.name}(const char * val) {
% for value in decl.values:
if (strcmp("${value}", val) == 0)
return ${value};
% endfor
assert(false);
return (enum ${decl.name}) -1;
}
% endif
% if isinstance(decl, intel_device_info.Struct):
static JSON_Value *
dump_${decl.name}(const struct ${decl.name} *arg) {
JSON_Value *val = json_value_init_object();
JSON_Object *json = json_object(val);
% for member in decl.members:
% if member.member_type in intel_device_info.INT_TYPES:
% if member.array:
{
JSON_Value *jtmp = json_value_init_array();
JSON_Array *jarray = json_array(jtmp);
for (unsigned i = 0; i < sizeof(arg->${member.name}) / sizeof(*arg->${member.name}); ++i)
json_array_append_number(jarray, arg->${member.name}[i]);
json_object_set_value(json, "${member.name}", jtmp);
}
% else:
json_object_set_number(json, "${member.name}", arg->${member.name});
% endif
% elif member.member_type == "char":
json_object_set_string(json, "${member.name}", arg->${member.name});
% elif member.member_type == "bool":
json_object_set_boolean(json, "${member.name}", arg->${member.name});
% elif isinstance(intel_device_info.TYPES_BY_NAME[member.member_type], intel_device_info.Enum):
json_object_set_value(json, "${member.name}", dump_${member.member_type}(arg->${member.name}));
% elif isinstance(intel_device_info.TYPES_BY_NAME[member.member_type], intel_device_info.Struct):
% if member.array:
{
JSON_Value *jtmp = json_value_init_array();
JSON_Array *jarray = json_array(jtmp);
for (unsigned i = 0; i < sizeof(arg->${member.name}) / sizeof(*arg->${member.name}); ++i)
json_array_append_value(jarray, dump_${member.member_type}(&arg->${member.name}[i]));
json_object_set_value(json, "${member.name}", jtmp);
}
% else:
json_object_set_value(json, "${member.name}", dump_${member.member_type}(&arg->${member.name}));
% endif
% endif
% endfor
return val;
}
static void
load_${decl.name}(JSON_Object *json, struct ${decl.name} *target) {
% for member in decl.members:
% if member.member_type in intel_device_info.INT_TYPES:
% if member.array:
{
JSON_Array *array = json_object_get_array(json, "${member.name}");
for (unsigned i = 0; i < json_array_get_count(array); ++i)
target->${member.name}[i] = json_array_get_number(array, i);
}
% else:
target->${member.name} = json_object_get_number(json, "${member.name}");
% endif
% elif member.member_type == "char":
strncpy(target->${member.name},
json_object_get_string(json, "${member.name}"),
sizeof(target->${member.name}) - 1);
% elif member.member_type == "bool":
target->${member.name} = json_object_get_boolean(json, "${member.name}");
% elif isinstance(intel_device_info.TYPES_BY_NAME[member.member_type], intel_device_info.Enum):
target->${member.name} = load_${member.member_type}(json_object_get_string(json, "${member.name}"));
% elif isinstance(intel_device_info.TYPES_BY_NAME[member.member_type], intel_device_info.Struct):
% if member.array:
{
JSON_Array *array = json_object_get_array(json, "${member.name}");
for (unsigned i = 0; i < json_array_get_count(array); ++i)
load_${member.member_type}(json_array_get_object(array, i), target->${member.name} + i);
}
% else:
load_${member.member_type}(json_object_get_object(json, "${member.name}"), &target->${member.name});
% endif
% endif
% endfor
}
% endif
% endfor
bool
intel_device_info_from_json(const char *path,
struct intel_device_info *devinfo) {
JSON_Value *root = json_parse_file(path);
JSON_Object *obj = json_object(root);
const char *devinfo_type_blake3 = "${checksum}";
/* verify that json was generated with a compatible driver */
if (strncmp(devinfo_type_blake3,
json_object_get_string(obj, "devinfo_type_blake3"),
strlen(devinfo_type_blake3)))
return false;
load_intel_device_info(obj, devinfo);
/* override no_hw to indicate that the GPU has been stubbed */
devinfo->no_hw = true;
json_value_free(root);
intel_device_info_init_was(devinfo);
return true;
}
JSON_Value *
intel_device_info_dump_json(const struct intel_device_info *devinfo) {
JSON_Value * root = dump_intel_device_info(devinfo);
/* record a hash of the structure type declaration, to prevent loading with
* an incompatible driver
*/
JSON_Object *obj = json_object(root);
json_object_set_string(obj, "devinfo_type_blake3", "${checksum}");
return root;
}
"""
def declaration_checksum(typename):
"""Calculate a stable checksum for the struct that will change whenever any
of the members change. We will refer to this value as the 'type declaration hash'"""
h = hashlib.new('sha1')
struct_description = TYPES_BY_NAME[typename]
for member in struct_description.members:
h.update(member.name.encode(encoding="utf-8"))
h.update(f"{member.array}".encode(encoding="utf-8"))
member_type = member.member_type
if member_type in FUNDAMENTAL_TYPES:
h.update(member_type.encode(encoding="utf-8"))
elif isinstance(TYPES_BY_NAME[member_type], Enum):
h.update(member_type.encode(encoding="utf-8"))
else:
# encode the type declaration hash for the nested struct
h.update(declaration_checksum(member_type).encode(encoding="utf-8"))
return h.hexdigest()
def main():
"""print intel_device_serialize.c at the specified path"""
if len(sys.argv) > 1:
outf = open(sys.argv[1], 'w', encoding='utf-8')
else:
outf = sys.stdout
try:
outf.write(Template(template).render(TYPES=TYPES,
checksum=declaration_checksum("intel_device_info")))
except:
print(exceptions.text_error_template().render(
TYPES=TYPES,
checksum=declaration_checksum("intel_device_info")))
sys.exit(1)
outf.close()
if __name__ == "__main__":
main()
+37
View File
@@ -0,0 +1,37 @@
#undef NDEBUG
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include "intel_device_info.h"
#include "intel_device_info_test.h"
int
main(int argc, char *argv[])
{
struct {
uint32_t pci_id;
const char *name;
} chipsets[] = {
#undef CHIPSET
#define CHIPSET(id, family, family_str, str_name, ...) { .pci_id = id, .name = str_name, },
#include "pci_ids/iris_pci_ids.h"
#include "pci_ids/crocus_pci_ids.h"
};
for (uint32_t i = 0; i < ARRAY_SIZE(chipsets); i++) {
struct intel_device_info devinfo = { 0, };
char force_probe[10];
int len = snprintf(force_probe, sizeof force_probe, "%x",
chipsets[i].pci_id);
assert(len < sizeof force_probe);
os_set_option("INTEL_FORCE_PROBE", force_probe, true);
assert(intel_get_device_info_from_pci_id(chipsets[i].pci_id, &devinfo));
verify_device_info(&devinfo);
}
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
#undef NDEBUG
#include <assert.h>
#include "intel_device_info.h"
static void
verify_device_info(const struct intel_device_info *devinfo)
{
assert(devinfo->ver != 0);
assert((devinfo->verx10 / 10) == devinfo->ver);
assert(devinfo->max_eus_per_subslice != 0);
assert(devinfo->num_thread_per_eu != 0);
assert(devinfo->timestamp_frequency != 0);
assert(devinfo->ver < 7 || devinfo->max_constant_urb_size_kb > 0);
assert(devinfo->ver < 8 || devinfo->max_threads_per_psd > 0);
assert(devinfo->platform >= 1);
assert(devinfo->num_slices <= ARRAY_SIZE(devinfo->subslice_masks));
assert(devinfo->num_slices <= devinfo->max_slices);
assert(intel_device_info_subslice_total(devinfo) <=
(devinfo->max_slices * devinfo->max_subslices_per_slice));
for (uint32_t s = 0; s < ARRAY_SIZE(devinfo->num_subslices); s++)
assert(devinfo->num_subslices[s] <= devinfo->max_subslices_per_slice);
assert(__builtin_popcount(devinfo->slice_masks) <= devinfo->max_slices);
uint32_t total_subslices = 0;
for (size_t i = 0; i < ARRAY_SIZE(devinfo->subslice_masks); i++)
total_subslices += __builtin_popcount(devinfo->subslice_masks[i]);
assert(total_subslices <=
(devinfo->max_slices * devinfo->max_subslices_per_slice));
assert(intel_device_info_eu_total(devinfo) > 0);
assert(intel_device_info_subslice_total(devinfo) > 0);
total_subslices = 0;
for (uint32_t s = 0; s < devinfo->max_slices; s++)
for (uint32_t ss = 0; ss < devinfo->max_subslices_per_slice; ss++)
total_subslices += intel_device_info_subslice_available(devinfo, s, ss);
assert(total_subslices == intel_device_info_subslice_total(devinfo));
uint32_t total_eus = 0;
for (uint32_t s = 0; s < devinfo->max_slices; s++)
for (uint32_t ss = 0; ss < devinfo->max_subslices_per_slice; ss++)
for (uint32_t eu = 0; eu < devinfo->max_eus_per_subslice; eu++)
total_eus += intel_device_info_eu_available(devinfo, s, ss, eu);
assert(total_eus == intel_device_info_eu_total(devinfo));
}
+414
View File
@@ -0,0 +1,414 @@
/*
* Copyright © 2021 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "intel_device_info.h"
#include "intel_hwconfig.h"
#include "intel_hwconfig_types.h"
#include "intel/common/intel_gem.h"
#include "i915/intel_device_info.h"
#include "xe/intel_device_info.h"
#include "util/log.h"
struct hwconfig {
uint32_t key;
uint32_t len;
uint32_t val[];
};
static char *
key_to_name(uint32_t key)
{
#define HANDLE(key_name) case key_name: return #key_name
switch (key) {
HANDLE(INTEL_HWCONFIG_MAX_SLICES_SUPPORTED);
HANDLE(INTEL_HWCONFIG_MAX_DUAL_SUBSLICES_SUPPORTED);
HANDLE(INTEL_HWCONFIG_MAX_NUM_EU_PER_DSS);
HANDLE(INTEL_HWCONFIG_NUM_PIXEL_PIPES);
HANDLE(INTEL_HWCONFIG_DEPRECATED_MAX_NUM_GEOMETRY_PIPES);
HANDLE(INTEL_HWCONFIG_DEPRECATED_L3_CACHE_SIZE_IN_KB);
HANDLE(INTEL_HWCONFIG_DEPRECATED_L3_BANK_COUNT);
HANDLE(INTEL_HWCONFIG_L3_CACHE_WAYS_SIZE_IN_BYTES);
HANDLE(INTEL_HWCONFIG_L3_CACHE_WAYS_PER_SECTOR);
HANDLE(INTEL_HWCONFIG_MAX_MEMORY_CHANNELS);
HANDLE(INTEL_HWCONFIG_MEMORY_TYPE);
HANDLE(INTEL_HWCONFIG_CACHE_TYPES);
HANDLE(INTEL_HWCONFIG_LOCAL_MEMORY_PAGE_SIZES_SUPPORTED);
HANDLE(INTEL_HWCONFIG_DEPRECATED_SLM_SIZE_IN_KB);
HANDLE(INTEL_HWCONFIG_NUM_THREADS_PER_EU);
HANDLE(INTEL_HWCONFIG_TOTAL_VS_THREADS);
HANDLE(INTEL_HWCONFIG_TOTAL_GS_THREADS);
HANDLE(INTEL_HWCONFIG_TOTAL_HS_THREADS);
HANDLE(INTEL_HWCONFIG_TOTAL_DS_THREADS);
HANDLE(INTEL_HWCONFIG_TOTAL_VS_THREADS_POCS);
HANDLE(INTEL_HWCONFIG_TOTAL_PS_THREADS);
HANDLE(INTEL_HWCONFIG_DEPRECATED_MAX_FILL_RATE);
HANDLE(INTEL_HWCONFIG_MAX_RCS);
HANDLE(INTEL_HWCONFIG_MAX_CCS);
HANDLE(INTEL_HWCONFIG_MAX_VCS);
HANDLE(INTEL_HWCONFIG_MAX_VECS);
HANDLE(INTEL_HWCONFIG_MAX_COPY_CS);
HANDLE(INTEL_HWCONFIG_DEPRECATED_URB_SIZE_IN_KB);
HANDLE(INTEL_HWCONFIG_MIN_VS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_VS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MIN_PCS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_PCS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MIN_HS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_HS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MIN_GS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_GS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MIN_DS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_DS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_PUSH_CONSTANT_URB_RESERVED_SIZE);
HANDLE(INTEL_HWCONFIG_POCS_PUSH_CONSTANT_URB_RESERVED_SIZE);
HANDLE(INTEL_HWCONFIG_URB_REGION_ALIGNMENT_SIZE_IN_BYTES);
HANDLE(INTEL_HWCONFIG_URB_ALLOCATION_SIZE_UNITS_IN_BYTES);
HANDLE(INTEL_HWCONFIG_MAX_URB_SIZE_CCS_IN_BYTES);
HANDLE(INTEL_HWCONFIG_VS_MIN_DEREF_BLOCK_SIZE_HANDLE_COUNT);
HANDLE(INTEL_HWCONFIG_DS_MIN_DEREF_BLOCK_SIZE_HANDLE_COUNT);
HANDLE(INTEL_HWCONFIG_NUM_RT_STACKS_PER_DSS);
HANDLE(INTEL_HWCONFIG_MAX_URB_STARTING_ADDRESS);
HANDLE(INTEL_HWCONFIG_MIN_CS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_CS_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_URB);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_REST);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_DC);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_RO);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_Z);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_COLOR);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_UNIFIED_TILE_CACHE);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_COMMAND_BUFFER);
HANDLE(INTEL_HWCONFIG_L3_ALLOC_PER_BANK_RW);
HANDLE(INTEL_HWCONFIG_MAX_NUM_L3_CONFIGS);
HANDLE(INTEL_HWCONFIG_BINDLESS_SURFACE_OFFSET_BIT_COUNT);
HANDLE(INTEL_HWCONFIG_RESERVED_CCS_WAYS);
HANDLE(INTEL_HWCONFIG_CSR_SIZE_IN_MB);
HANDLE(INTEL_HWCONFIG_GEOMETRY_PIPES_PER_SLICE);
HANDLE(INTEL_HWCONFIG_L3_BANK_SIZE_IN_KB);
HANDLE(INTEL_HWCONFIG_SLM_SIZE_PER_DSS);
HANDLE(INTEL_HWCONFIG_MAX_PIXEL_FILL_RATE_PER_SLICE);
HANDLE(INTEL_HWCONFIG_MAX_PIXEL_FILL_RATE_PER_DSS);
HANDLE(INTEL_HWCONFIG_URB_SIZE_PER_SLICE_IN_KB);
HANDLE(INTEL_HWCONFIG_URB_SIZE_PER_L3_BANK_COUNT_IN_KB);
HANDLE(INTEL_HWCONFIG_MAX_SUBSLICE);
HANDLE(INTEL_HWCONFIG_MAX_EU_PER_SUBSLICE);
HANDLE(INTEL_HWCONFIG_RAMBO_L3_BANK_SIZE_IN_KB);
HANDLE(INTEL_HWCONFIG_SLM_SIZE_PER_SS_IN_KB);
HANDLE(INTEL_HWCONFIG_NUM_HBM_STACKS_PER_TILE);
HANDLE(INTEL_HWCONFIG_NUM_CHANNELS_PER_HBM_STACK);
HANDLE(INTEL_HWCONFIG_HBM_CHANNEL_WIDTH_IN_BYTES);
HANDLE(INTEL_HWCONFIG_MIN_TASK_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_TASK_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MIN_MESH_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_MESH_URB_ENTRIES);
HANDLE(INTEL_HWCONFIG_MAX_GSC);
HANDLE(INTEL_HWCONFIG_SYNC_NUM_RT_STACKS_PER_DSS);
HANDLE(INTEL_HWCONFIG_NUM_XECU);
#undef HANDLE
}
return "UNKNOWN_INTEL_HWCONFIG";
}
typedef void (*hwconfig_item_cb)(struct intel_device_info *devinfo,
const struct hwconfig *item);
static void
process_hwconfig_table(struct intel_device_info *devinfo,
const struct hwconfig *hwconfig,
int32_t hwconfig_len,
hwconfig_item_cb item_callback_func)
{
assert(hwconfig);
assert(hwconfig_len % 4 == 0);
const struct hwconfig *current = hwconfig;
const struct hwconfig *end =
(struct hwconfig*)(((uint32_t*)hwconfig) + (hwconfig_len / 4));
while (current < end) {
assert(current + 1 < end);
struct hwconfig *next =
(struct hwconfig*)((uint32_t*)current + 2 + current->len);
assert(next <= end);
item_callback_func(devinfo, current);
current = next;
}
assert(current == end);
}
bool
intel_hwconfig_is_required(const struct intel_device_info *devinfo)
{
/* returns is true when the platform should apply hwconfig values */
return devinfo->verx10 >= 125;
}
static bool
hwconfig_ignore_difference(const struct intel_device_info *devinfo,
const uint32_t key, uint32_t value)
{
if (key == INTEL_HWCONFIG_TOTAL_GS_THREADS && value == 336 &&
intel_needs_workaround(devinfo, 18040209780))
return true;
return false;
}
static inline void
hwconfig_item_warning(const struct intel_device_info *devinfo,
const char *devinfo_name, uint32_t devinfo_val,
const uint32_t hwconfig_key, uint32_t hwconfig_val)
{
if (devinfo_val != hwconfig_val &&
!hwconfig_ignore_difference(devinfo, hwconfig_key, hwconfig_val)) {
printf(" %s (%u) != devinfo->%s (%u)\n", key_to_name(hwconfig_key),
hwconfig_val, devinfo_name, devinfo_val);
}
}
static inline bool
should_apply_hwconfig_item(uint16_t always_apply_verx10,
const struct intel_device_info *devinfo,
uint32_t devinfo_val)
{
assert(intel_hwconfig_is_required(devinfo));
if ((devinfo->verx10 >= always_apply_verx10 || devinfo_val == 0))
return true;
return false;
}
/* If apply_hwconfig(devinfo) is true, then we apply the
* hwconfig value to the devinfo field, ``F``.
*
* For debug builds, if apply_hwconfig() is false, we will compare the
* hwconfig value, ``V``, with the current value in ``F`` and log a warning
* message if they differ. This should help to make sure the values in our
* devinfo structures match what hwconfig is specified.
*
* If ``devinfo->verx10 >= CVER``, then the hwconfig value is always be used.
* If ``devinfo->verx10 < CVER``, the hwconfig value is only used if
* devinfo->F is 0.
*/
#define DEVINFO_HWCONFIG_KV(CVER, F, K, V) \
do { \
if (check_only) \
hwconfig_item_warning(devinfo, #F, devinfo->F, (K), (V)); \
else if (should_apply_hwconfig_item((CVER), devinfo, devinfo->F)) \
devinfo->F = (V); \
} while (0)
#define DEVINFO_HWCONFIG(CVER, F, I) \
DEVINFO_HWCONFIG_KV((CVER), F, (I)->key, (I)->val[0])
#define CALC_TOPOLOGY_LAYOUT_VERX10 300
static void
process_hwconfig_item(struct intel_device_info *devinfo,
const struct hwconfig *item,
const bool check_only)
{
switch (item->key) {
case INTEL_HWCONFIG_MAX_SLICES_SUPPORTED:
/* if we are not applying hwconfig to max_slices and max_subslices_per_slice
* it should be skipped at all, otherwise the upper limit values set in
* xe_compute_topology() will cause hwconfig mismatch warnings in
* some SKUs.
*/
if (devinfo->verx10 < CALC_TOPOLOGY_LAYOUT_VERX10)
break;
DEVINFO_HWCONFIG(CALC_TOPOLOGY_LAYOUT_VERX10, max_slices, item);
break;
case INTEL_HWCONFIG_MAX_DUAL_SUBSLICES_SUPPORTED: /* available in Gfx 12.5 */
case INTEL_HWCONFIG_MAX_SUBSLICE: /* available in Gfx 20+ */
if (devinfo->verx10 < CALC_TOPOLOGY_LAYOUT_VERX10)
break;
/* This one is special because it depends on max_slices that is not
* guarantee to be processed before this one
*/
if (check_only) {
hwconfig_item_warning(devinfo, "max_subslices_per_slice",
devinfo->max_subslices_per_slice, item->key,
item->val[0] / devinfo->max_slices);
} else {
/* it will be later adjusted in late_apply_hwconfig() */
DEVINFO_HWCONFIG(CALC_TOPOLOGY_LAYOUT_VERX10,
max_subslices_per_slice, item);
}
break;
case INTEL_HWCONFIG_MAX_NUM_EU_PER_DSS:
DEVINFO_HWCONFIG(125, max_eus_per_subslice, item);
break;
case INTEL_HWCONFIG_NUM_THREADS_PER_EU:
DEVINFO_HWCONFIG(125, num_thread_per_eu, item);
break;
case INTEL_HWCONFIG_TOTAL_VS_THREADS:
DEVINFO_HWCONFIG(125, max_vs_threads, item);
break;
case INTEL_HWCONFIG_TOTAL_GS_THREADS:
DEVINFO_HWCONFIG(125, max_gs_threads, item);
break;
case INTEL_HWCONFIG_TOTAL_HS_THREADS:
DEVINFO_HWCONFIG(125, max_tcs_threads, item);
break;
case INTEL_HWCONFIG_TOTAL_DS_THREADS:
DEVINFO_HWCONFIG(125, max_tes_threads, item);
break;
case INTEL_HWCONFIG_TOTAL_VS_THREADS_POCS:
break; /* ignore */
case INTEL_HWCONFIG_TOTAL_PS_THREADS: {
unsigned threads = item->val[0];
if (devinfo->ver == 12)
threads /= 2;
DEVINFO_HWCONFIG_KV(125, max_threads_per_psd, item->key, threads);
break;
}
case INTEL_HWCONFIG_URB_SIZE_PER_SLICE_IN_KB:
DEVINFO_HWCONFIG(125, urb.size, item);
break;
case INTEL_HWCONFIG_MAX_VS_URB_ENTRIES:
DEVINFO_HWCONFIG(200, urb.max_entries[MESA_SHADER_VERTEX], item);
break;
case INTEL_HWCONFIG_MAX_HS_URB_ENTRIES:
DEVINFO_HWCONFIG(200, urb.max_entries[MESA_SHADER_TESS_CTRL], item);
break;
case INTEL_HWCONFIG_MAX_GS_URB_ENTRIES:
DEVINFO_HWCONFIG(200, urb.max_entries[MESA_SHADER_GEOMETRY], item);
break;
case INTEL_HWCONFIG_MAX_DS_URB_ENTRIES:
DEVINFO_HWCONFIG(200, urb.max_entries[MESA_SHADER_TESS_EVAL], item);
break;
case INTEL_HWCONFIG_NUM_PIXEL_PIPES:
DEVINFO_HWCONFIG_KV(200, num_color_pipes, item->key, item->val[0]);
break;
case INTEL_HWCONFIG_GEOMETRY_PIPES_PER_SLICE:
DEVINFO_HWCONFIG_KV(200, num_geom_pipes, item->key, item->val[0]);
break;
default:
break; /* ignore */
}
}
static void
apply_hwconfig_item(struct intel_device_info *devinfo,
const struct hwconfig *item)
{
process_hwconfig_item(devinfo, item, false);
}
static void
late_apply_hwconfig(struct intel_device_info *devinfo)
{
if (devinfo->verx10 >= CALC_TOPOLOGY_LAYOUT_VERX10) {
assert((devinfo->max_subslices_per_slice % devinfo->max_slices) == 0);
devinfo->max_subslices_per_slice /= devinfo->max_slices;
}
/* Calculate total pipes count from stored values */
if (devinfo->verx10 >= 200) {
devinfo->num_color_pipes *= devinfo->max_slices;
devinfo->num_depth_pipes = devinfo->num_color_pipes;
devinfo->num_geom_pipes *= devinfo->max_slices;
}
}
bool
intel_hwconfig_process_table(struct intel_device_info *devinfo,
void *data, int32_t len)
{
if (intel_hwconfig_is_required(devinfo)) {
process_hwconfig_table(devinfo, data, len, apply_hwconfig_item);
late_apply_hwconfig(devinfo);
}
return true;
}
static void
print_hwconfig_item(struct intel_device_info *devinfo,
const struct hwconfig *item)
{
printf("%s: ", key_to_name(item->key));
for (int i = 0; i < item->len; i++)
printf(i ? ", 0x%x (%d)" : "0x%x (%d)", item->val[i],
item->val[i]);
printf("\n");
}
static void
intel_print_hwconfig_table(const struct hwconfig *hwconfig,
int32_t hwconfig_len)
{
process_hwconfig_table(NULL, hwconfig, hwconfig_len, print_hwconfig_item);
}
static struct hwconfig *
intel_get_hwconfig_table(int fd, struct intel_device_info *devinfo,
int32_t *hwconfig_len)
{
switch (devinfo->kmd_type) {
case INTEL_KMD_TYPE_I915:
return intel_device_info_i915_query_hwconfig(fd, hwconfig_len);
case INTEL_KMD_TYPE_XE:
return intel_device_info_xe_query_hwconfig(fd, hwconfig_len);
default:
UNREACHABLE("unknown kmd type");
return NULL;
}
}
void
intel_get_and_print_hwconfig_table(int fd, struct intel_device_info *devinfo)
{
struct hwconfig *hwconfig;
int32_t hwconfig_len = 0;
hwconfig = intel_get_hwconfig_table(fd, devinfo, &hwconfig_len);
if (hwconfig) {
intel_print_hwconfig_table(hwconfig, hwconfig_len);
free(hwconfig);
}
}
UNUSED static void
check_hwconfig_item(struct intel_device_info *devinfo,
const struct hwconfig *item)
{
process_hwconfig_item(devinfo, item, true);
}
void
intel_check_hwconfig_items(int fd, struct intel_device_info *devinfo)
{
struct hwconfig *data;
int32_t len = 0;
data = intel_get_hwconfig_table(fd, devinfo, &len);
if (data) {
process_hwconfig_table(devinfo, data, len, check_hwconfig_item);
free(data);
}
}
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright © 2021 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.
*
*/
#ifndef INTEL_HWCONFIG_H
#define INTEL_HWCONFIG_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct intel_device_info;
bool
intel_hwconfig_process_table(struct intel_device_info *devinfo, void *data,
int32_t len);
void
intel_check_hwconfig_items(int fd, struct intel_device_info *devinfo);
void
intel_get_and_print_hwconfig_table(int fd, struct intel_device_info *devinfo);
bool
intel_hwconfig_is_required(const struct intel_device_info *devinfo);
#ifdef __cplusplus
}
#endif
#endif /* INTEL_DEVICE_INFO_H */
+119
View File
@@ -0,0 +1,119 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2021 Intel Corporation
*/
#ifndef _INTEL_HWCONFIG_TYPES_H_
#define _INTEL_HWCONFIG_TYPES_H_
/**
* enum intel_hwconfig - Global definition of hwconfig table attributes
*
* Intel devices provide a KLV (Key/Length/Value) table containing
* the static hardware configuration for that platform.
* This enum defines the current attribute keys for this KLV.
*/
enum intel_hwconfig {
INTEL_HWCONFIG_MAX_SLICES_SUPPORTED = 1,
INTEL_HWCONFIG_MAX_DUAL_SUBSLICES_SUPPORTED, /* 2 */
INTEL_HWCONFIG_MAX_NUM_EU_PER_DSS, /* 3 */
INTEL_HWCONFIG_NUM_PIXEL_PIPES, /* 4 */
INTEL_HWCONFIG_DEPRECATED_MAX_NUM_GEOMETRY_PIPES, /* 5 */
INTEL_HWCONFIG_DEPRECATED_L3_CACHE_SIZE_IN_KB, /* 6 */
INTEL_HWCONFIG_DEPRECATED_L3_BANK_COUNT, /* 7 */
INTEL_HWCONFIG_L3_CACHE_WAYS_SIZE_IN_BYTES, /* 8 */
INTEL_HWCONFIG_L3_CACHE_WAYS_PER_SECTOR, /* 9 */
INTEL_HWCONFIG_MAX_MEMORY_CHANNELS, /* 10 */
INTEL_HWCONFIG_MEMORY_TYPE, /* 11 */
INTEL_HWCONFIG_CACHE_TYPES, /* 12 */
INTEL_HWCONFIG_LOCAL_MEMORY_PAGE_SIZES_SUPPORTED, /* 13 */
INTEL_HWCONFIG_DEPRECATED_SLM_SIZE_IN_KB, /* 14 */
INTEL_HWCONFIG_NUM_THREADS_PER_EU, /* 15 */
INTEL_HWCONFIG_TOTAL_VS_THREADS, /* 16 */
INTEL_HWCONFIG_TOTAL_GS_THREADS, /* 17 */
INTEL_HWCONFIG_TOTAL_HS_THREADS, /* 18 */
INTEL_HWCONFIG_TOTAL_DS_THREADS, /* 19 */
INTEL_HWCONFIG_TOTAL_VS_THREADS_POCS, /* 20 */
INTEL_HWCONFIG_TOTAL_PS_THREADS, /* 21 */
INTEL_HWCONFIG_DEPRECATED_MAX_FILL_RATE, /* 22 */
INTEL_HWCONFIG_MAX_RCS, /* 23 */
INTEL_HWCONFIG_MAX_CCS, /* 24 */
INTEL_HWCONFIG_MAX_VCS, /* 25 */
INTEL_HWCONFIG_MAX_VECS, /* 26 */
INTEL_HWCONFIG_MAX_COPY_CS, /* 27 */
INTEL_HWCONFIG_DEPRECATED_URB_SIZE_IN_KB, /* 28 */
INTEL_HWCONFIG_MIN_VS_URB_ENTRIES, /* 29 */
INTEL_HWCONFIG_MAX_VS_URB_ENTRIES, /* 30 */
INTEL_HWCONFIG_MIN_PCS_URB_ENTRIES, /* 31 */
INTEL_HWCONFIG_MAX_PCS_URB_ENTRIES, /* 32 */
INTEL_HWCONFIG_MIN_HS_URB_ENTRIES, /* 33 */
INTEL_HWCONFIG_MAX_HS_URB_ENTRIES, /* 34 */
INTEL_HWCONFIG_MIN_GS_URB_ENTRIES, /* 35 */
INTEL_HWCONFIG_MAX_GS_URB_ENTRIES, /* 36 */
INTEL_HWCONFIG_MIN_DS_URB_ENTRIES, /* 37 */
INTEL_HWCONFIG_MAX_DS_URB_ENTRIES, /* 38 */
INTEL_HWCONFIG_PUSH_CONSTANT_URB_RESERVED_SIZE, /* 39 */
INTEL_HWCONFIG_POCS_PUSH_CONSTANT_URB_RESERVED_SIZE, /* 40 */
INTEL_HWCONFIG_URB_REGION_ALIGNMENT_SIZE_IN_BYTES, /* 41 */
INTEL_HWCONFIG_URB_ALLOCATION_SIZE_UNITS_IN_BYTES, /* 42 */
INTEL_HWCONFIG_MAX_URB_SIZE_CCS_IN_BYTES, /* 43 */
INTEL_HWCONFIG_VS_MIN_DEREF_BLOCK_SIZE_HANDLE_COUNT, /* 44 */
INTEL_HWCONFIG_DS_MIN_DEREF_BLOCK_SIZE_HANDLE_COUNT, /* 45 */
INTEL_HWCONFIG_NUM_RT_STACKS_PER_DSS, /* 46 */
INTEL_HWCONFIG_MAX_URB_STARTING_ADDRESS, /* 47 */
INTEL_HWCONFIG_MIN_CS_URB_ENTRIES, /* 48 */
INTEL_HWCONFIG_MAX_CS_URB_ENTRIES, /* 49 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_URB, /* 50 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_REST, /* 51 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_DC, /* 52 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_RO, /* 53 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_Z, /* 54 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_COLOR, /* 55 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_UNIFIED_TILE_CACHE, /* 56 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_COMMAND_BUFFER, /* 57 */
INTEL_HWCONFIG_L3_ALLOC_PER_BANK_RW, /* 58 */
INTEL_HWCONFIG_MAX_NUM_L3_CONFIGS, /* 59 */
INTEL_HWCONFIG_BINDLESS_SURFACE_OFFSET_BIT_COUNT, /* 60 */
INTEL_HWCONFIG_RESERVED_CCS_WAYS, /* 61 */
INTEL_HWCONFIG_CSR_SIZE_IN_MB, /* 62 */
INTEL_HWCONFIG_GEOMETRY_PIPES_PER_SLICE, /* 63 */
INTEL_HWCONFIG_L3_BANK_SIZE_IN_KB, /* 64 */
INTEL_HWCONFIG_SLM_SIZE_PER_DSS, /* 65 */
INTEL_HWCONFIG_MAX_PIXEL_FILL_RATE_PER_SLICE, /* 66 */
INTEL_HWCONFIG_MAX_PIXEL_FILL_RATE_PER_DSS, /* 67 */
INTEL_HWCONFIG_URB_SIZE_PER_SLICE_IN_KB, /* 68 */
INTEL_HWCONFIG_URB_SIZE_PER_L3_BANK_COUNT_IN_KB, /* 69 */
INTEL_HWCONFIG_MAX_SUBSLICE, /* 70 */
INTEL_HWCONFIG_MAX_EU_PER_SUBSLICE, /* 71 */
INTEL_HWCONFIG_RAMBO_L3_BANK_SIZE_IN_KB, /* 72 */
INTEL_HWCONFIG_SLM_SIZE_PER_SS_IN_KB, /* 73 */
INTEL_HWCONFIG_NUM_HBM_STACKS_PER_TILE, /* 74 */
INTEL_HWCONFIG_NUM_CHANNELS_PER_HBM_STACK, /* 75 */
INTEL_HWCONFIG_HBM_CHANNEL_WIDTH_IN_BYTES, /* 76 */
INTEL_HWCONFIG_MIN_TASK_URB_ENTRIES, /* 77 */
INTEL_HWCONFIG_MAX_TASK_URB_ENTRIES, /* 78 */
INTEL_HWCONFIG_MIN_MESH_URB_ENTRIES, /* 79 */
INTEL_HWCONFIG_MAX_MESH_URB_ENTRIES, /* 80 */
INTEL_HWCONFIG_MAX_GSC, /* 81 */
INTEL_HWCONFIG_SYNC_NUM_RT_STACKS_PER_DSS, /* 82 */
INTEL_HWCONFIG_NUM_XECU, /* 83 */
__INTEL_HWCONFIG_LIMIT
};
enum {
INTEL_HWCONFIG_MEMORY_TYPE_LPDDR4 = 0,
INTEL_HWCONFIG_MEMORY_TYPE_LPDDR5,
INTEL_HWCONFIG_MEMORY_TYPE_HBM2,
INTEL_HWCONFIG_MEMORY_TYPE_HBM2e,
INTEL_HWCONFIG_MEMORY_TYPE_GDDR6,
__INTEL_HWCONFIG_MEMORY_TYPE_LIMIT
};
enum {
INTEL_HWCONFIG_CACHE_TYPE_L3 = 0,
INTEL_HWCONFIG_CACHE_TYPE_LLC,
INTEL_HWCONFIG_CACHE_TYPE_EDRAM,
__INTEL_HWCONFIG_CACHE_TYPE_LIMIT
};
#endif /* _INTEL_HWCONFIG_TYPES_H_ */
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright © 2023 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <string.h>
#include "util/libdrm.h"
#include "virtio/intel_virtio.h"
#include "intel_kmd.h"
enum intel_kmd_type
intel_get_kmd_type(int fd)
{
enum intel_kmd_type type = INTEL_KMD_TYPE_INVALID;
drmVersionPtr version = drmGetVersion(fd);
if (!version)
return type;
/*
* For virtio, version->name would be either "virtio_gpu" or "i915",
* depending on whether vtest is used or not.
*/
if (strcmp(version->name, "i915") == 0 || is_intel_virtio_fd(fd))
type = INTEL_KMD_TYPE_I915;
else if (strcmp(version->name, "xe") == 0)
type = INTEL_KMD_TYPE_XE;
drmFreeVersion(version);
return type;
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright © 2023 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.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
enum intel_kmd_type {
INTEL_KMD_TYPE_INVALID = 0,
INTEL_KMD_TYPE_I915,
INTEL_KMD_TYPE_XE,
INTEL_KMD_TYPE_STUB, /* Only used by ANV to run tests */
INTEL_KMD_TYPE_LAST
};
enum intel_kmd_type intel_get_kmd_type(int fd);
#ifdef __cplusplus
}
#endif
File diff suppressed because it is too large. Load diff
+122
View File
@@ -0,0 +1,122 @@
# Copyright © 2017 Intel Corporation
# SPDX-License-Identifier: MIT
# TODO: android?
files_libintel_dev = files(
'i915/intel_device_info.c',
'i915/intel_device_info.h',
'xe/intel_device_info.c',
'xe/intel_device_info.h',
'intel_debug.c',
'intel_debug.h',
'intel_device_info.c',
'intel_device_info.h',
'intel_hwconfig.c',
'intel_hwconfig.h',
'intel_kmd.c',
'intel_kmd.h',
)
inc_intel_dev_virtio = []
link_intel_dev_virtio = []
if with_intel_virtio
files_libintel_dev += files(
'virtio/intel_virtio_bo.c',
'virtio/intel_virtio_device.c',
'virtio/i915_virtio_ccmd.c',
'virtio/i915_virtio_ccmd_execbuf.c',
)
inc_intel_dev_virtio += [
inc_virtio_gpu,
inc_virtio_vdrm,
]
link_intel_dev_virtio += [ libvdrm ]
endif
intel_dev_wa_src = custom_target('intel_wa.[ch]',
input : ['gen_wa_helpers.py', 'mesa_defs.json'],
output : ['intel_wa.h', 'intel_wa.c'],
command : [prog_python, '@INPUT@', '@OUTPUT@'])
intel_dev_info_gen_src = custom_target('intel_device_info_gen.h',
input : 'intel_device_info_gen_h.py',
depend_files: 'intel_device_info.py',
output : ['intel_device_info_gen.h'],
command : [prog_python, '@INPUT@', '@OUTPUT@'])
intel_dev_serialize_src = custom_target('intel_device_info_serialize_gen.c',
input : 'intel_device_info_serialize_gen_c.py',
depend_files: 'intel_device_info.py',
output : ['intel_device_info_serialize_gen.c'],
command : [prog_python, '@INPUT@', '@OUTPUT@'])
# ensures intel_wa.h exists before implementation files are compiled
idep_intel_dev_wa = declare_dependency(sources : [intel_dev_wa_src[0]])
idep_intel_dev_info_gen = declare_dependency(sources : [intel_dev_info_gen_src[0]])
libintel_dev = static_library(
'intel_dev',
[files_libintel_dev, sha1_h, [intel_dev_wa_src]],
include_directories : [inc_include, inc_src, inc_intel, inc_intel_dev_virtio],
dependencies : [dep_libdrm, idep_mesautil, idep_intel_dev_wa,
idep_intel_dev_info_gen],
c_args : [no_override_init_args, soong_compat_c_args],
gnu_symbol_visibility : 'hidden',
link_with : [link_intel_dev_virtio],
)
idep_intel_dev = declare_dependency(
link_with : libintel_dev,
dependencies : [idep_intel_dev_wa, idep_intel_dev_info_gen, idep_mesautil],
sources : [intel_dev_info_gen_src, intel_dev_wa_src[0]],
)
if with_tests
test('intel_device_info_test',
executable(
'intel_device_info_test',
'intel_device_info_test.c',
include_directories : [inc_include, inc_src, inc_intel],
dependencies : idep_intel_dev,
),
suite : ['intel'],
)
endif
if with_tests and with_tools.contains('drm-shim') and with_tools.contains('intel')
platforms = [ [ 70, ['ivb', 'byt'] ],
[ 75, ['hsw'] ],
[ 80, ['bdw', 'chv'] ],
[ 90, ['skl', 'kbl', 'aml', 'cml', 'whl', 'bxt', 'glk'] ],
[ 110, ['icl', 'ehl', 'jsl'] ],
[ 120, ['tgl', 'rkl', 'adl', 'rpl', 'dg1', 'sg1'] ],
[ 125, ['dg2'] ],
]
intel_devinfo_override_test = executable(
'intel_device_info_override_test',
'intel_device_info_override_test.c',
dependencies : [dep_libdrm, idep_intel_dev],
include_directories : [inc_include, inc_src, inc_intel],
)
intel_drm_ld_preload = join_paths(meson.current_build_dir(), '..', 'tools', 'libintel_noop_drm_shim.so')
foreach _gens : platforms
gen = _gens[0]
foreach p : _gens[1]
test('intel_device_info_override_test_@0@'.format(p),
intel_devinfo_override_test,
args : '@0@'.format(gen),
env : [
'LD_PRELOAD=@0@'.format(intel_drm_ld_preload),
'INTEL_STUB_GPU_PLATFORM=@0@'.format(p),
'STRACEDIR=meson-logs/strace/intel_device_info_override_test_@0@'.format(p),
],
suite : ['intel'],
)
endforeach
endforeach
endif
+220
View File
@@ -0,0 +1,220 @@
/*
* Copyright 2025 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#ifndef I915_VIRTIO_PROTO_H_
#define I915_VIRTIO_PROTO_H_
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic error "-Wpadded"
#endif
#define I915_STATIC_ASSERT_SIZE(t) \
static_assert(sizeof(struct t) % 8 == 0, "sizeof(struct " #t ") not multiple of 8"); \
static_assert(alignof(struct t) <= 8, "alignof(struct " #t ") too large");
#define I915_DEFINE_CAST(parent, child) \
I915_STATIC_ASSERT_SIZE(child) \
DEFINE_CAST(parent, child) \
enum i915_ccmd {
I915_CCMD_IOCTL_SIMPLE = 1,
I915_CCMD_GETPARAM,
I915_CCMD_QUERYPARAM,
I915_CCMD_GEM_CREATE,
I915_CCMD_GEM_CREATE_EXT,
I915_CCMD_GEM_CONTEXT_CREATE,
I915_CCMD_GEM_EXECBUFFER2,
I915_CCMD_GEM_SET_MMAP_MODE,
I915_CCMD_GEM_BUSY,
};
#define I915_CCMD(_cmd, _len) (struct vdrm_ccmd_req){ \
.cmd = I915_CCMD_##_cmd, \
.len = (_len), \
}
/**
* Defines the layout of shmem buffer used for host->guest communication.
*/
struct i915_shmem {
struct vdrm_shmem base;
/**
* Bitmask of banned GEM context IDs.
*/
uint64_t banned_ctx_mask;
};
DEFINE_CAST(vdrm_shmem, i915_shmem)
/*
* I915_CCMD_IOCTL_SIMPLE
*/
struct i915_ccmd_ioctl_simple_req {
struct vdrm_ccmd_req hdr;
uint32_t cmd;
uint32_t pad;
uint8_t payload[];
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_ioctl_simple_req)
struct i915_ccmd_ioctl_simple_rsp {
struct vdrm_ccmd_rsp hdr;
int32_t ret;
uint8_t payload[];
};
I915_STATIC_ASSERT_SIZE(i915_ccmd_ioctl_simple_rsp)
/*
* I915_CCMD_GETPARAM
*/
struct i915_ccmd_getparam_req {
struct vdrm_ccmd_req hdr;
uint32_t param;
uint32_t value;
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_getparam_req)
struct i915_ccmd_getparam_rsp {
struct vdrm_ccmd_rsp hdr;
uint32_t pad;
int32_t ret;
uint32_t value;
};
I915_STATIC_ASSERT_SIZE(i915_ccmd_getparam_rsp)
/*
* I915_CCMD_QUERYPARAM
*/
struct i915_ccmd_queryparam_req {
struct vdrm_ccmd_req hdr;
uint32_t query_id;
uint32_t length;
uint32_t flags;
uint32_t pad;
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_queryparam_req)
struct i915_ccmd_queryparam_rsp {
struct vdrm_ccmd_rsp hdr;
uint32_t pad;
int32_t ret;
int32_t length;
uint8_t payload[];
};
I915_STATIC_ASSERT_SIZE(i915_ccmd_queryparam_rsp)
/*
* I915_CCMD_GEM_CONTEXT_CREATE
*/
struct i915_ccmd_gem_context_create_req {
struct vdrm_ccmd_req hdr;
uint32_t flags;
uint32_t params_size;
uint8_t payload[];
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_gem_context_create_req)
struct i915_ccmd_gem_context_create_rsp {
struct vdrm_ccmd_rsp hdr;
uint32_t pad;
int32_t ret;
uint32_t ctx_id;
};
I915_STATIC_ASSERT_SIZE(i915_ccmd_gem_context_create_rsp)
/*
* I915_CCMD_GEM_CREATE
*/
struct i915_ccmd_gem_create_req {
struct vdrm_ccmd_req hdr;
uint64_t size;
uint32_t blob_id;
uint32_t pad;
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_gem_create_req)
/*
* I915_CCMD_GEM_CREATE_EXT
*/
struct i915_ccmd_gem_create_ext_req {
struct vdrm_ccmd_req hdr;
uint64_t size;
uint32_t blob_id;
uint32_t gem_flags;
uint32_t ext_size;
uint32_t pad;
uint8_t payload[];
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_gem_create_ext_req)
/*
* I915_CCMD_GEM_EXECBUFFER2
*/
struct i915_ccmd_gem_execbuffer2_req {
struct vdrm_ccmd_req hdr;
uint64_t flags;
uint64_t context_id;
uint32_t buffer_count;
uint32_t batch_start_offset;
uint32_t batch_len;
uint32_t relocs_count;
uint8_t payload[];
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_gem_execbuffer2_req)
struct i915_ccmd_gem_execbuffer2_rsp {
struct vdrm_ccmd_rsp hdr;
int32_t ret;
};
I915_STATIC_ASSERT_SIZE(i915_ccmd_gem_execbuffer2_rsp)
/*
* I915_CCMD_GEM_SET_MMAP_MODE
*/
struct i915_ccmd_gem_set_mmap_mode_req {
struct vdrm_ccmd_req hdr;
uint32_t res_id;
uint32_t flags;
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_gem_set_mmap_mode_req)
/*
* I915_CCMD_GEM_BUSY
*/
struct i915_ccmd_gem_busy_req {
struct vdrm_ccmd_req hdr;
uint32_t res_id;
uint32_t pad;
};
I915_DEFINE_CAST(vdrm_ccmd_req, i915_ccmd_gem_busy_req)
struct i915_ccmd_gem_busy_rsp {
struct vdrm_ccmd_rsp hdr;
uint32_t pad;
int32_t ret;
int32_t busy;
};
I915_STATIC_ASSERT_SIZE(i915_ccmd_gem_busy_rsp)
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
#endif /* I915_VIRTIO_PROTO_H_ */
+866
View File
@@ -0,0 +1,866 @@
/*
* Copyright 2024 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#include "intel_virtio_priv.h"
#include "i915_proto.h"
static int
i915_virtio_simple_ioctl(struct intel_virtio_device *dev,
unsigned cmd, void *_req)
{
unsigned req_len = sizeof(struct i915_ccmd_ioctl_simple_req);
unsigned rsp_len = sizeof(struct i915_ccmd_ioctl_simple_rsp);
bool sync = !!(cmd & IOC_OUT);
int err;
req_len += _IOC_SIZE(cmd);
if (cmd & IOC_OUT)
rsp_len += _IOC_SIZE(cmd);
uint8_t buf[req_len];
struct i915_ccmd_ioctl_simple_req *req = (void *)(uintptr_t)buf;
struct i915_ccmd_ioctl_simple_rsp *rsp;
req->hdr = I915_CCMD(IOCTL_SIMPLE, req_len);
req->cmd = cmd;
memcpy(req->payload, _req, _IOC_SIZE(cmd));
rsp = vdrm_alloc_rsp(dev->vdrm, &req->hdr, rsp_len);
err = vdrm_send_req(dev->vdrm, &req->hdr, sync);
if (err)
return errno;
if (cmd & IOC_OUT) {
memcpy(_req, rsp->payload, _IOC_SIZE(cmd));
return rsp->ret;
}
return 0;
}
static int
i915_virtio_queryparam(struct intel_virtio_device *dev,
struct drm_i915_query *query)
{
struct drm_i915_query_item *item = (void *)(uintptr_t)query->items_ptr;
struct i915_ccmd_queryparam_rsp *rsp;
struct i915_ccmd_queryparam_req req;
int err;
if (query->num_items != 1) {
mesa_loge("unsupported number of query items");
return EINVAL;
}
req.hdr = I915_CCMD(QUERYPARAM, sizeof(req));
req.query_id = item->query_id;
req.length = item->length;
req.flags = item->flags;
rsp = vdrm_alloc_rsp(dev->vdrm, &req.hdr, sizeof(*rsp) + item->length);
err = vdrm_send_req(dev->vdrm, &req.hdr, true);
if (err)
return errno;
if (item->data_ptr && rsp->length > 0)
memcpy((void *)(uintptr_t)item->data_ptr, rsp->payload, rsp->length);
item->length = rsp->length;
return rsp->ret;
}
static int
i915_virtio_getparam(struct intel_virtio_device *dev,
struct drm_i915_getparam *gp)
{
struct i915_ccmd_getparam_rsp *rsp;
struct i915_ccmd_getparam_req req;
int err;
req.hdr = I915_CCMD(GETPARAM, sizeof(req));
req.param = gp->param;
rsp = vdrm_alloc_rsp(dev->vdrm, &req.hdr, sizeof(*rsp));
err = vdrm_send_req(dev->vdrm, &req.hdr, true);
if (err)
return errno;
*gp->value = rsp->value;
return rsp->ret;
}
static int
i915_virtio_gem_create(struct intel_virtio_device *dev,
struct drm_i915_gem_create *create)
{
uint32_t blob_flags = VIRTGPU_BLOB_FLAG_USE_MAPPABLE |
VIRTGPU_BLOB_FLAG_USE_SHAREABLE;
if (dev->vdrm->supports_cross_device)
blob_flags |= VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE;
struct i915_ccmd_gem_create_req req = {
.hdr = I915_CCMD(GEM_CREATE, sizeof(req)),
.size = create->size,
};
/* tunneled cmds are processed separately on host side,
* before the renderer->get_blob() callback.. the blob_id
* is used to like the created bo to the get_blob() call
*/
req.blob_id = p_atomic_inc_return(&dev->next_blob_id);
int ret = vdrm_bo_create(dev->vdrm, create->size, blob_flags,
req.blob_id, &req.hdr);
if (!ret)
return EINVAL;
create->handle = ret;
return 0;
}
static int
i915_virtio_gem_create_ext(struct intel_virtio_device *dev,
struct drm_i915_gem_create_ext *create)
{
struct i915_user_extension *extension = (void *)(uintptr_t)create->extensions;
unsigned ext_size = 0;
void *payload_ptr;
while (extension) {
switch (extension->name) {
case I915_GEM_CREATE_EXT_MEMORY_REGIONS:
{
struct drm_i915_gem_create_ext_memory_regions *mem_regions;
mem_regions = (void*)(uintptr_t)extension;
ext_size += sizeof(*mem_regions);
ext_size += sizeof(struct drm_i915_gem_memory_class_instance) * mem_regions->num_regions;
break;
}
case I915_GEM_CREATE_EXT_PROTECTED_CONTENT:
ext_size += sizeof(struct drm_i915_gem_create_ext_protected_content);
break;
case I915_GEM_CREATE_EXT_SET_PAT:
ext_size += sizeof(struct drm_i915_gem_create_ext_set_pat);
break;
default:
mesa_loge("unsupported extension %d", extension->name);
return EINVAL;
}
extension = (void *)(uintptr_t)extension->next_extension;
}
unsigned req_len = sizeof(struct i915_ccmd_gem_create_ext_req);
req_len += ext_size;
uint8_t buf[req_len];
struct i915_ccmd_gem_create_ext_req *req = (void *)(uintptr_t)buf;
extension = (void *)(uintptr_t)create->extensions;
payload_ptr = req->payload;
while (extension) {
switch (extension->name) {
case I915_GEM_CREATE_EXT_MEMORY_REGIONS:
{
struct drm_i915_gem_create_ext_memory_regions *mem_regions;
struct drm_i915_gem_memory_class_instance *instances;
mem_regions = (void*)(uintptr_t)extension;
instances = (void*)(uintptr_t)mem_regions->regions;
memcpy(payload_ptr, mem_regions, sizeof(*mem_regions));
payload_ptr += sizeof(*mem_regions);
memcpy(payload_ptr, instances, sizeof(*instances) * mem_regions->num_regions);
payload_ptr += sizeof(*instances) * mem_regions->num_regions;
break;
}
case I915_GEM_CREATE_EXT_PROTECTED_CONTENT:
memcpy(payload_ptr, extension, sizeof(struct drm_i915_gem_create_ext_protected_content));
payload_ptr += sizeof(struct drm_i915_gem_create_ext_protected_content);
break;
case I915_GEM_CREATE_EXT_SET_PAT:
memcpy(payload_ptr, extension, sizeof(struct drm_i915_gem_create_ext_set_pat));
payload_ptr += sizeof(struct drm_i915_gem_create_ext_set_pat);
break;
default:
mesa_loge("unsupported extension");
return EINVAL;
}
extension = (void *)(uintptr_t)extension->next_extension;
}
req->hdr = I915_CCMD(GEM_CREATE_EXT, req_len);
req->gem_flags = create->flags;
req->ext_size = ext_size;
req->size = create->size;
uint32_t blob_flags = VIRTGPU_BLOB_FLAG_USE_MAPPABLE |
VIRTGPU_BLOB_FLAG_USE_SHAREABLE;
if (dev->vdrm->supports_cross_device)
blob_flags |= VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE;
/* tunneled cmds are processed separately on host side,
* before the renderer->get_blob() callback.. the blob_id
* is used to like the created bo to the get_blob() call
*/
req->blob_id = p_atomic_inc_return(&dev->next_blob_id);
int ret = vdrm_bo_create(dev->vdrm, create->size, blob_flags,
req->blob_id, &req->hdr);
if (!ret)
return EINVAL;
create->handle = ret;
return 0;
}
static int
i915_virtio_gem_close(struct intel_virtio_device *dev,
struct drm_gem_close *close)
{
vdrm_bo_close(dev->vdrm, close->handle);
return 0;
}
static int
i915_virtio_gem_context_create_ext(struct intel_virtio_device *dev,
struct drm_i915_gem_context_create_ext *create)
{
struct drm_i915_gem_context_create_ext_setparam *setparam;
struct i915_ccmd_gem_context_create_rsp *rsp;
unsigned params_size = 0;
void *payload_ptr;
int err;
if (!(create->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS))
return i915_virtio_simple_ioctl(dev, DRM_IOCTL_I915_GEM_CONTEXT_CREATE,
create);
setparam = (void *)(uintptr_t)create->extensions;
while (setparam) {
switch (setparam->param.param) {
case I915_CONTEXT_PARAM_BAN_PERIOD:
case I915_CONTEXT_PARAM_NO_ZEROMAP:
case I915_CONTEXT_PARAM_GTT_SIZE:
case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
case I915_CONTEXT_PARAM_BANNABLE:
case I915_CONTEXT_PARAM_PRIORITY:
case I915_CONTEXT_PARAM_SSEU:
case I915_CONTEXT_PARAM_RECOVERABLE:
case I915_CONTEXT_PARAM_VM:
case I915_CONTEXT_PARAM_ENGINES:
case I915_CONTEXT_PARAM_PERSISTENCE:
case I915_CONTEXT_PARAM_RINGSIZE:
case I915_CONTEXT_PARAM_PROTECTED_CONTENT:
break;
default:
mesa_loge("unsupported context param");
return EINVAL;
}
params_size += sizeof(*setparam) + setparam->param.size;
setparam = (void *)(uintptr_t)setparam->base.next_extension;
}
unsigned req_len = sizeof(struct i915_ccmd_gem_context_create_req);
req_len += params_size;
uint8_t buf[req_len];
struct i915_ccmd_gem_context_create_req *req = (void *)(uintptr_t)buf;
setparam = (void *)(uintptr_t)create->extensions;
payload_ptr = req->payload;
while (setparam) {
memcpy(payload_ptr, setparam, sizeof(*setparam));
payload_ptr += sizeof(*setparam);
if (setparam->param.size) {
memcpy(payload_ptr, (void*)(uintptr_t)setparam->param.value,
setparam->param.size);
payload_ptr += setparam->param.size;
}
setparam = (void *)(uintptr_t)setparam->base.next_extension;
}
req->hdr = I915_CCMD(GEM_CONTEXT_CREATE, req_len);
req->params_size = params_size;
req->flags = create->flags;
rsp = vdrm_alloc_rsp(dev->vdrm, &req->hdr, sizeof(*rsp));
err = vdrm_send_req(dev->vdrm, &req->hdr, true);
if (err)
return errno;
create->ctx_id = rsp->ctx_id;
return rsp->ret;
}
static int
i915_virtio_gem_context_param(struct intel_virtio_device *dev,
unsigned long cmd,
struct drm_i915_gem_context_param *param)
{
switch (param->param) {
case I915_CONTEXT_PARAM_RECOVERABLE:
case I915_CONTEXT_PARAM_PRIORITY:
case I915_CONTEXT_PARAM_GTT_SIZE:
case I915_CONTEXT_PARAM_VM:
return i915_virtio_simple_ioctl(dev, cmd, param);
default:
mesa_loge("unsupported context param");
return EINVAL;
}
}
static int
intel_virtio_ioctl_errno(int fd, unsigned long cmd, void *req)
{
int err = ioctl(fd, cmd, req);
if (!err)
errno = 0;
return errno;
}
static int
i915_virtio_gem_busy(struct intel_virtio_device *dev,
struct drm_i915_gem_busy *busy)
{
struct drm_virtgpu_3d_wait virt_wait = {
.handle = busy->handle,
.flags = VIRTGPU_WAIT_NOWAIT,
};
intel_virtio_ioctl_errno(dev->fd, DRM_IOCTL_VIRTGPU_WAIT, &virt_wait);
if (errno == EBUSY) {
errno = 0;
busy->busy = 1;
} else if (!errno) {
busy->busy = 0;
}
return errno;
}
static int
i915_virtio_gem_wait(struct intel_virtio_device *dev,
struct drm_i915_gem_wait *wait)
{
struct drm_virtgpu_3d_wait virt_wait = { .handle = wait->bo_handle };
if (!wait->timeout_ns)
virt_wait.flags = VIRTGPU_WAIT_NOWAIT;
intel_virtio_ioctl_errno(dev->fd, DRM_IOCTL_VIRTGPU_WAIT, &virt_wait);
if (errno == EBUSY)
errno = ETIME;
return errno;
}
static int
i915_virtio_gem_busy_vpipe(struct intel_virtio_device *dev,
struct drm_i915_gem_busy *busy)
{
struct i915_ccmd_gem_busy_rsp *rsp;
struct i915_ccmd_gem_busy_req req;
int err;
req.hdr = I915_CCMD(GEM_BUSY, sizeof(req));
req.res_id = vdrm_handle_to_res_id(dev->vdrm, busy->handle);
rsp = vdrm_alloc_rsp(dev->vdrm, &req.hdr, sizeof(*rsp));
err = vdrm_send_req(dev->vdrm, &req.hdr, true);
if (err)
return errno;
busy->busy = (rsp->busy != 0);
return rsp->ret;
}
static int64_t time_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000LL + ts.tv_nsec;
}
static int
i915_virtio_gem_wait_vpipe(struct intel_virtio_device *dev,
struct drm_i915_gem_wait *wait)
{
do {
struct drm_i915_gem_busy busy = { .handle = wait->bo_handle };
int64_t start_time = time_ns();
int err = i915_virtio_gem_busy_vpipe(dev, &busy);
if (err)
return err;
wait->timeout_ns -= time_ns() - start_time;
if (wait->timeout_ns < 0)
wait->timeout_ns = 0;
if (!busy.busy)
return 0;
if (wait->timeout_ns)
sched_yield();
} while (wait->timeout_ns);
return ETIME;
}
static int
i915_virtio_simple_ioctl_gem_patched(struct intel_virtio_device *dev,
unsigned long cmd, void *req)
{
uint32_t *handle = req;
uint32_t tmp_handle = *handle;
*handle = vdrm_handle_to_res_id(dev->vdrm, *handle);
errno = i915_virtio_simple_ioctl(dev, cmd, req);
*handle = tmp_handle;
return errno;
}
static int
i915_virtio_gem_vm_control(struct intel_virtio_device *dev,
unsigned long cmd,
struct drm_i915_gem_vm_control *vm)
{
if (vm->extensions) {
mesa_loge("unsupported vm extension");
return EINVAL;
}
if (vm->flags) {
mesa_loge("unsupported vm flags");
return EINVAL;
}
return i915_virtio_simple_ioctl(dev, cmd, vm);
}
static int
i915_virtio_get_reset_stats(struct intel_virtio_device *dev,
unsigned long cmd,
struct drm_i915_reset_stats *stats)
{
struct i915_shmem *shmem = to_i915_shmem(dev->vdrm->shmem);
if (stats->ctx_id >= 64 ||
!(p_atomic_read(&shmem->banned_ctx_mask) & (1ULL << stats->ctx_id)))
return 0;
errno = i915_virtio_simple_ioctl(dev, cmd, stats);
return errno;
}
static int
i915_virtio_gem_mmap_offset(struct intel_virtio_device *dev,
unsigned long cmd,
struct drm_i915_gem_mmap_offset *mmap_offset)
{
struct i915_ccmd_gem_set_mmap_mode_req req;
int err;
req.hdr = I915_CCMD(GEM_SET_MMAP_MODE, sizeof(req));
req.res_id = vdrm_handle_to_res_id(dev->vdrm, mmap_offset->handle);
req.flags = mmap_offset->flags;
err = vdrm_send_req(dev->vdrm, &req.hdr, false);
if (err)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_wait(struct intel_virtio_device *dev,
struct drm_syncobj_wait *args)
{
int ret = dev->sync->wait(dev->sync,
(uint32_t*)(uintptr_t)args->handles,
args->count_handles,
args->timeout_nsec, args->flags,
&args->first_signaled);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_create(struct intel_virtio_device *dev,
struct drm_syncobj_create *args)
{
int ret = dev->sync->create(dev->sync, args->flags, &args->handle);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_destroy(struct intel_virtio_device *dev,
struct drm_syncobj_destroy *args)
{
int ret = dev->sync->destroy(dev->sync, args->handle);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_reset(struct intel_virtio_device *dev,
struct drm_syncobj_array *args)
{
int ret = dev->sync->reset(dev->sync, (uint32_t*)(uintptr_t)args->handles,
args->count_handles);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_signal(struct intel_virtio_device *dev,
struct drm_syncobj_array *args)
{
int ret = dev->sync->signal(dev->sync, (uint32_t*)(uintptr_t)args->handles,
args->count_handles);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_timeline_signal(struct intel_virtio_device *dev,
struct drm_syncobj_timeline_array *args)
{
int ret = dev->sync->timeline_signal(dev->sync,
(uint32_t*)(uintptr_t)args->handles,
(uint64_t*)(uintptr_t)args->points,
args->count_handles);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_timeline_wait(struct intel_virtio_device *dev,
struct drm_syncobj_timeline_wait *args)
{
int ret = dev->sync->timeline_wait(dev->sync,
(uint32_t*)(uintptr_t)args->handles,
(uint64_t*)(uintptr_t)args->points,
args->count_handles,
args->timeout_nsec, args->flags,
&args->first_signaled);
if (ret < 0)
return -ret;
return 0;
}
static int
intel_virtio_sync_syncobj_transfer(struct intel_virtio_device *dev,
struct drm_syncobj_transfer *args)
{
int ret = dev->sync->transfer(dev->sync, args->dst_handle, args->dst_point,
args->src_handle, args->src_point, args->flags);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_query(struct intel_virtio_device *dev,
struct drm_syncobj_timeline_array *args)
{
int ret = dev->sync->query(dev->sync,
(uint32_t*)(uintptr_t)args->handles,
(uint64_t*)(uintptr_t)args->points,
args->count_handles,
args->flags);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_fd_to_handle(struct intel_virtio_device *dev,
unsigned long cmd,
struct drm_syncobj_handle *args)
{
if (args->flags)
assert(!dev->vpipe);
if (!dev->vpipe)
return intel_virtio_ioctl_errno(dev->fd, cmd, args);
int ret = dev->sync->fd_to_handle(dev->sync, args->fd, &args->handle);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_sync_syncobj_handle_to_fd(struct intel_virtio_device *dev,
unsigned long cmd,
struct drm_syncobj_handle *args)
{
if (args->flags)
assert(!dev->vpipe);
if (!dev->vpipe)
return intel_virtio_ioctl_errno(dev->fd, cmd, args);
int ret = dev->sync->handle_to_fd(dev->sync, args->handle, &args->fd);
if (ret < 0)
return errno;
return 0;
}
static int
intel_virtio_prime_fd_to_handle(struct intel_virtio_device *dev,
struct drm_prime_handle *args)
{
args->handle = vdrm_dmabuf_to_handle(dev->vdrm, args->fd);
if (!args->handle) {
errno = EINVAL;
return errno;
}
return 0;
}
static int
intel_virtio_prime_handle_to_fd(struct intel_virtio_device *dev,
struct drm_prime_handle *args)
{
args->fd = vdrm_bo_export_dmabuf(dev->vdrm, args->handle);
if (args->fd < 0) {
errno = EINVAL;
return errno;
}
return 0;
}
int
intel_virtio_ioctl(int fd, unsigned long cmd, void *req)
{
int orig_errno = errno;
struct intel_virtio_device *dev = fd_to_intel_virtio_device(fd);
if (!dev) {
errno = orig_errno;
/* this is a real phys device if not bound to virtio */
return ioctl(fd, cmd, req);
}
/*
* Special case for legacy ioctls that have same NR as extended ioctl
* and need to be handled differently.
*/
switch (cmd) {
case DRM_IOCTL_I915_GEM_CREATE:
errno = i915_virtio_gem_create(dev, req);
goto out;
case DRM_IOCTL_I915_GEM_CONTEXT_CREATE:
errno = i915_virtio_simple_ioctl(dev, cmd, req);
goto out;
default:
break;
}
#define IOC_MASKED(IOC) ((IOC) & ~IOCSIZE_MASK)
/* DRM ioctls vary in size depending on a used UAPI header version */
switch (IOC_MASKED(cmd)) {
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_WAIT):
errno = intel_virtio_sync_syncobj_wait(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_CREATE):
errno = intel_virtio_sync_syncobj_create(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_DESTROY):
errno = intel_virtio_sync_syncobj_destroy(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_RESET):
errno = intel_virtio_sync_syncobj_reset(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_SIGNAL):
errno = intel_virtio_sync_syncobj_signal(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL):
errno = intel_virtio_sync_syncobj_timeline_signal(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT):
errno = intel_virtio_sync_syncobj_timeline_wait(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_TRANSFER):
errno = intel_virtio_sync_syncobj_transfer(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_QUERY):
errno = intel_virtio_sync_syncobj_query(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE):
errno = intel_virtio_sync_syncobj_fd_to_handle(dev, cmd, req);
break;
case IOC_MASKED(DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD):
errno = intel_virtio_sync_syncobj_handle_to_fd(dev, cmd, req);
break;
case IOC_MASKED(DRM_IOCTL_PRIME_HANDLE_TO_FD):
errno = intel_virtio_prime_handle_to_fd(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_PRIME_FD_TO_HANDLE):
errno = intel_virtio_prime_fd_to_handle(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_CREATE_EXT):
errno = i915_virtio_gem_create_ext(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GETPARAM):
errno = i915_virtio_getparam(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_QUERY):
errno = i915_virtio_queryparam(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_GEM_CLOSE):
errno = i915_virtio_gem_close(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT):
errno = i915_virtio_gem_context_create_ext(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM):
case IOC_MASKED(DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM):
errno = i915_virtio_gem_context_param(dev, cmd, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_EXECBUFFER2):
errno = i915_virtio_gem_execbuffer2(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_MADVISE):
errno = 0;
break;
case IOC_MASKED(DRM_IOCTL_I915_GET_RESET_STATS):
errno = i915_virtio_get_reset_stats(dev, cmd, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_REG_READ):
case IOC_MASKED(DRM_IOCTL_I915_GEM_CONTEXT_DESTROY):
case IOC_MASKED(DRM_IOCTL_I915_GEM_GET_APERTURE):
errno = i915_virtio_simple_ioctl(dev, cmd, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_GET_TILING):
case IOC_MASKED(DRM_IOCTL_I915_GEM_SET_TILING):
case IOC_MASKED(DRM_IOCTL_I915_GEM_SET_DOMAIN):
errno = i915_virtio_simple_ioctl_gem_patched(dev, cmd, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_BUSY):
/*
* vpipe doesn't support tracking busy GEMs, use GEM-busy CCMD that
* is added specifically for vpipe purposes.
*/
if (dev->vpipe)
errno = i915_virtio_gem_busy_vpipe(dev, req);
else
errno = i915_virtio_gem_busy(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_WAIT):
if (dev->vpipe)
errno = i915_virtio_gem_wait_vpipe(dev, req);
else
errno = i915_virtio_gem_wait(dev, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_VM_CREATE):
case IOC_MASKED(DRM_IOCTL_I915_GEM_VM_DESTROY):
errno = i915_virtio_gem_vm_control(dev, cmd, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_MMAP_OFFSET):
errno = i915_virtio_gem_mmap_offset(dev, cmd, req);
break;
case IOC_MASKED(DRM_IOCTL_I915_GEM_USERPTR):
errno = ENODEV;
break;
default:
mesa_loge("unsupported ioctl 0x%lx\n", _IOC_NR(cmd));
errno = ENOTTY;
break;
}
#undef IOC_MASKED
out:
if (errno) {
mesa_logd("ioctl 0x%lx failed errno=%d\n", _IOC_NR(cmd), errno);
return -1;
}
errno = orig_errno;
return 0;
}
@@ -0,0 +1,199 @@
/*
* Copyright 2024 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#include "intel_virtio_priv.h"
#include "i915_proto.h"
struct virtio_gem_execbuffer_params {
struct intel_virtio_device *dev;
struct drm_i915_gem_execbuffer2 *exec;
struct drm_virtgpu_execbuffer_syncobj *in_syncobjs;
unsigned num_in_syncobjs;
struct drm_virtgpu_execbuffer_syncobj *out_syncobjs;
unsigned num_out_syncobjs;
uint32_t *bo_handles;
unsigned num_bo_handles;
};
static int
i915_virtio_gem_execbuffer2_submit(struct virtio_gem_execbuffer_params *params)
{
struct intel_virtio_device *dev = params->dev;
struct i915_shmem *shmem = to_i915_shmem(dev->vdrm->shmem);
struct drm_i915_gem_execbuffer2 *exec = params->exec;
struct drm_i915_gem_exec_object2 *buffers = (void *)(uintptr_t)exec->buffers_ptr;
struct drm_i915_gem_relocation_entry *relocs;
struct i915_ccmd_gem_execbuffer2_rsp *rsp;
uint64_t allowed_flags = 0, flags = exec->flags;
if (exec->rsvd1 < 64 &&
(p_atomic_read(&shmem->banned_ctx_mask) & (1ULL << exec->rsvd1)))
return EIO;
unsigned relocs_count = 0;
for (int i = 0; i < exec->buffer_count; i++)
relocs_count += buffers[i].relocation_count;
size_t buffers_size = sizeof(*buffers) * exec->buffer_count;
size_t relocations_size = sizeof(struct drm_i915_gem_relocation_entry) * relocs_count;
unsigned req_len = sizeof(struct i915_ccmd_gem_execbuffer2_req);
req_len += buffers_size + relocations_size;
uint8_t buf[req_len];
struct i915_ccmd_gem_execbuffer2_req *req = (void *)buf;
memcpy(req->payload, buffers, buffers_size);
uint32_t bo_handles[exec->buffer_count + 1];
buffers = (void *)req->payload;
relocs = (void *)(req->payload + buffers_size);
for (int i = 0; i < exec->buffer_count; i++) {
memcpy(relocs, (void *)(uintptr_t)buffers[i].relocs_ptr,
sizeof(*relocs) * buffers[i].relocation_count);
relocs += buffers[i].relocation_count;
bo_handles[i] = buffers[i].handle;
buffers[i].handle = vdrm_handle_to_res_id(dev->vdrm, buffers[i].handle);
}
params->bo_handles = bo_handles;
params->num_bo_handles = exec->buffer_count;
allowed_flags |= I915_EXEC_RING_MASK;
allowed_flags |= I915_EXEC_CONSTANTS_MASK;
allowed_flags |= I915_EXEC_GEN7_SOL_RESET;
allowed_flags |= I915_EXEC_NO_RELOC;
allowed_flags |= I915_EXEC_HANDLE_LUT;
allowed_flags |= I915_EXEC_BSD_MASK << I915_EXEC_BSD_SHIFT;
allowed_flags |= I915_EXEC_BATCH_FIRST;
/* XXX: sanity-check flags, might be removed in a release version */
if (flags & ~(allowed_flags | I915_EXEC_FENCE_ARRAY | I915_EXEC_USE_EXTENSIONS)) {
mesa_loge("unsupported flags");
return EINVAL;
}
req->hdr = I915_CCMD(GEM_EXECBUFFER2, req_len);
req->relocs_count = relocs_count;
req->buffer_count = exec->buffer_count;
req->batch_start_offset = exec->batch_start_offset;
req->batch_len = exec->batch_len;
req->context_id = exec->rsvd1;
req->flags = flags & allowed_flags;
rsp = vdrm_alloc_rsp(dev->vdrm, &req->hdr, sizeof(*rsp));
struct vdrm_execbuf_params p = {
.req = &req->hdr,
.ring_idx = 1 + (flags & I915_EXEC_RING_MASK),
.in_syncobjs = params->in_syncobjs,
.num_in_syncobjs = params->num_in_syncobjs,
.out_syncobjs = params->out_syncobjs,
.num_out_syncobjs = params->num_out_syncobjs,
.handles = params->bo_handles,
.num_handles = params->num_bo_handles,
};
return vdrm_execbuf(dev->vdrm, &p);
}
int
i915_virtio_gem_execbuffer2(struct intel_virtio_device *dev,
struct drm_i915_gem_execbuffer2 *exec)
{
unsigned num_waits = 0, num_signals = 0, num_fences = 0, i, w, s;
struct drm_i915_gem_execbuffer_ext_timeline_fences *ext;
struct virtio_gem_execbuffer_params params;
struct drm_i915_gem_exec_fence *fences;
uint64_t *syncobj_values = NULL;
int ret;
memset(&params, 0, sizeof(params));
if (exec->flags & I915_EXEC_USE_EXTENSIONS) {
ext = (void *)(uintptr_t)exec->cliprects_ptr;
if (ext->base.name != DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES) {
mesa_loge("unsupported extension");
return EINVAL;
}
if (ext->base.next_extension) {
mesa_loge("unsupported extension");
return EINVAL;
}
num_fences = ext->fence_count;
fences = (void *)(uintptr_t)ext->handles_ptr;
syncobj_values = (void *)(uintptr_t)ext->values_ptr;
} else if (exec->flags & I915_EXEC_FENCE_ARRAY) {
fences = (void *)(uintptr_t)exec->cliprects_ptr;
num_fences = exec->num_cliprects;
}
for (i = 0; i < num_fences; i++) {
if (fences[i].flags & I915_EXEC_FENCE_WAIT)
num_waits++;
if (fences[i].flags & I915_EXEC_FENCE_SIGNAL)
num_signals++;
}
if (num_waits) {
params.in_syncobjs = calloc(sizeof(*params.in_syncobjs), num_waits);
if (!params.in_syncobjs) {
ret = ENOMEM;
goto out;
}
}
if (num_signals) {
params.out_syncobjs = calloc(sizeof(*params.out_syncobjs), num_signals);
if (!params.out_syncobjs) {
ret = ENOMEM;
goto out;
}
}
for (i = 0, w = 0, s = 0; i < num_fences; i++) {
if (fences[i].flags & I915_EXEC_FENCE_WAIT) {
params.in_syncobjs[w].handle = fences[i].handle;
if (syncobj_values)
params.in_syncobjs[w].point = syncobj_values[i];
w++;
}
if (fences[i].flags & I915_EXEC_FENCE_SIGNAL) {
params.out_syncobjs[s].handle = fences[i].handle;
if (syncobj_values)
params.out_syncobjs[s].point = syncobj_values[i];
s++;
}
if (!(fences[i].flags & (I915_EXEC_FENCE_WAIT | I915_EXEC_FENCE_SIGNAL))) {
mesa_loge("invalid fence flags");
ret = ENOMEM;
goto out;
}
}
params.dev = dev;
params.exec = exec;
params.num_in_syncobjs = num_waits;
params.num_out_syncobjs = num_signals;
ret = i915_virtio_gem_execbuffer2_submit(&params);
out:
free(params.out_syncobjs);
free(params.in_syncobjs);
return ret;
}
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright 2024 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#ifndef INTEL_VIRTIO_H_
#define INTEL_VIRTIO_H_
#include <stdbool.h>
#include <sys/mman.h>
#include "util/macros.h"
struct intel_device_info;
#ifdef HAVE_INTEL_VIRTIO
int intel_virtio_init_fd(int fd);
void intel_virtio_ref_fd(int fd);
void intel_virtio_unref_fd(int fd);
bool intel_virtio_get_pci_device_info(int fd,
struct intel_device_info *devinfo);
bool is_intel_virtio_fd(int fd);
void *intel_virtio_bo_mmap(int fd, uint32_t handle, size_t size, void *placed_addr);
struct util_sync_provider *intel_virtio_sync_provider(int fd);
#else
static inline int intel_virtio_init_fd(int fd)
{
return 0;
}
static inline void intel_virtio_ref_fd(int fd) {};
static inline void intel_virtio_unref_fd(int fd) {};
static inline bool
intel_virtio_get_pci_device_info(int fd, struct intel_device_info *devinfo)
{
return false;
}
static inline bool is_intel_virtio_fd(int fd)
{
return false;
}
static inline void *
intel_virtio_bo_mmap(int fd, uint32_t handle, size_t size, void *placed_addr)
{
return MAP_FAILED;
}
static struct util_sync_provider *
intel_virtio_sync_provider(int fd)
{
return NULL;
}
#endif /* HAVE_INTEL_VIRTIO */
#endif /* INTEL_VIRTIO_H_ */
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2024 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#include "intel_virtio_priv.h"
void *intel_virtio_bo_mmap(int fd, uint32_t handle, size_t size,
void *placed_addr)
{
struct intel_virtio_device *dev = fd_to_intel_virtio_device(fd);
if (!dev)
return MAP_FAILED;
void *map = vdrm_bo_map(dev->vdrm, handle, size, placed_addr);
if (!map) {
mesa_loge("failed to map bo");
return MAP_FAILED;
}
return map;
}
+168
View File
@@ -0,0 +1,168 @@
/*
* Copyright 2024 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#include "intel_device_info.h"
#include "intel_virtio_priv.h"
static simple_mtx_t dev_list_lock = SIMPLE_MTX_INITIALIZER;
static struct list_head dev_list = {
.next = &dev_list,
.prev = &dev_list,
};
/*
* Returns NULL if given FD isn't backed by virtio-intel device.
* Note this function is only used internally by the virtio-intel code,
* we don't expose struct intel_virtio_device globally.
*/
struct intel_virtio_device *
fd_to_intel_virtio_device(int fd)
{
struct intel_virtio_device *dev = NULL;
simple_mtx_lock(&dev_list_lock);
list_for_each_entry(struct intel_virtio_device, itr,
&dev_list, list_item) {
int err = os_same_file_description(itr->fd, fd);
if (!err) {
dev = itr;
break;
}
}
simple_mtx_unlock(&dev_list_lock);
return dev;
}
bool is_intel_virtio_fd(int fd)
{
return fd_to_intel_virtio_device(fd) != NULL;
}
bool
intel_virtio_get_pci_device_info(int fd, struct intel_device_info *devinfo)
{
struct intel_virtio_device *dev = fd_to_intel_virtio_device(fd);
struct virgl_renderer_capset_drm caps;
if (!dev)
return false;
caps = dev->vdrm->caps;
devinfo->pci_bus = caps.u.intel.pci_bus;
devinfo->pci_dev = caps.u.intel.pci_dev;
devinfo->pci_func = caps.u.intel.pci_func;
devinfo->pci_domain = caps.u.intel.pci_domain;
devinfo->pci_device_id = caps.u.intel.pci_device_id;
devinfo->pci_revision_id = caps.u.intel.pci_revision_id;
return true;
}
static bool is_virtio_fd(int fd)
{
drmVersionPtr version = drmGetVersion(fd);
bool is_virtio = !strcmp(version->name, "virtio_gpu");
drmFreeVersion(version);
if (debug_get_bool_option("INTEL_VIRTIO_FORCE_VTEST", false))
is_virtio = true;
return is_virtio;
}
static uint64_t
virtgpu_ioctl_getparam(int fd, uint64_t param)
{
/* val must be zeroed because kernel only writes the lower 32 bits */
uint64_t val = 0;
struct drm_virtgpu_getparam args = {
.param = param,
.value = (uintptr_t)&val,
};
const int ret = drmIoctl(fd, DRM_IOCTL_VIRTGPU_GETPARAM, &args);
return ret ? 0 : val;
}
int intel_virtio_init_fd(int fd)
{
if (!is_virtio_fd(fd))
return 0;
struct intel_virtio_device *dev = calloc(1, sizeof(*dev));
if (!dev)
return -ENOMEM;
if (debug_get_bool_option("INTEL_VIRTIO_FORCE_VTEST", false)) {
dev->vdrm = vdrm_device_connect(-1, VIRTGPU_DRM_CONTEXT_I915);
dev->vpipe = true;
} else {
dev->vdrm = vdrm_device_connect(fd, VIRTGPU_DRM_CONTEXT_I915);
}
if (!dev->vdrm) {
free(dev);
return -EINVAL;
}
if (dev->vpipe)
dev->sync = vdrm_vpipe_get_sync(dev->vdrm);
else
dev->sync = util_sync_provider_drm(fd);
if (!dev->sync) {
vdrm_device_close(dev->vdrm);
free(dev);
return -EINVAL;
}
dev->fd = os_dupfd_cloexec(fd);
p_atomic_set(&dev->refcnt, 1);
simple_mtx_lock(&dev_list_lock);
list_add(&dev->list_item, &dev_list);
simple_mtx_unlock(&dev_list_lock);
return 1;
}
void intel_virtio_ref_fd(int fd)
{
struct intel_virtio_device *dev = fd_to_intel_virtio_device(fd);
if (dev)
p_atomic_inc(&dev->refcnt);
}
void intel_virtio_unref_fd(int fd)
{
struct intel_virtio_device *dev = fd_to_intel_virtio_device(fd);
if (dev && !p_atomic_dec_return(&dev->refcnt)) {
simple_mtx_lock(&dev_list_lock);
list_del(&dev->list_item);
simple_mtx_unlock(&dev_list_lock);
dev->sync->finalize(dev->sync);
vdrm_device_close(dev->vdrm);
close(dev->fd);
free(dev);
}
}
struct util_sync_provider *intel_virtio_sync_provider(int fd)
{
struct intel_virtio_device *dev = fd_to_intel_virtio_device(fd);
if (dev)
return dev->sync;
return NULL;
}
+67
View File
@@ -0,0 +1,67 @@
/*
* Copyright 2024 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
#ifndef INTEL_VIRTIO_PRIV_H_
#define INTEL_VIRTIO_PRIV_H_
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "drm-uapi/drm.h"
#include "drm-uapi/i915_drm.h"
#include "drm-uapi/virtgpu_drm.h"
#include <xf86drm.h>
#include "util/libsync.h"
#include "util/list.h"
#include "util/log.h"
#include "util/macros.h"
#include "util/os_file.h"
#include "util/simple_mtx.h"
#include "util/u_atomic.h"
#include "util/u_debug.h"
#include "util/u_math.h"
#include "util/perf/cpu_trace.h"
#include "util/u_sync_provider.h"
#include "common/intel_gem.h"
#include "virtio/virtio-gpu/drm_hw.h"
#include "intel_virtio.h"
#include "vdrm.h"
#define virtio_ioctl(fd, name, args) ({ \
MESA_TRACE_SCOPE(#name); \
int ret = drmIoctl((fd), DRM_IOCTL_ ## name, (args)); \
ret; \
})
struct intel_virtio_device {
struct list_head list_item;
struct vdrm_device *vdrm;
struct util_sync_provider *sync;
int fd;
uint32_t next_blob_id;
uint32_t refcnt;
bool vpipe;
};
struct intel_virtio_device *fd_to_intel_virtio_device(int fd);
int i915_virtio_gem_execbuffer2(struct intel_virtio_device *dev,
struct drm_i915_gem_execbuffer2 *exec);
#endif /* INTEL_VIRTIO_PRIV_H_ */
+373
View File
@@ -0,0 +1,373 @@
/*
* Copyright © 2023 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "xe/intel_device_info.h"
#include "common/intel_gem.h"
#include "dev/intel_device_info.h"
#include "dev/intel_hwconfig.h"
#include "util/log.h"
#include "drm-uapi/xe_drm.h"
static inline bool
has_gmd_ip_version(const struct intel_device_info *devinfo)
{
return devinfo->verx10 >= 200;
}
static void *
xe_query_alloc_fetch(int fd, uint32_t query_id, int32_t *len)
{
struct drm_xe_device_query query = {
.query = query_id,
};
if (intel_ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query))
return NULL;
void *data = calloc(1, query.size);
if (!data)
return NULL;
query.data = (uintptr_t)data;
if (intel_ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query))
goto data_query_failed;
if (len)
*len = query.size;
return data;
data_query_failed:
free(data);
return NULL;
}
static bool
xe_query_config(int fd, struct intel_device_info *devinfo)
{
struct drm_xe_query_config *config;
config = xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_CONFIG, NULL);
if (!config)
return false;
if (config->info[DRM_XE_QUERY_CONFIG_FLAGS] & DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM)
devinfo->has_local_mem = true;
if (config->info[DRM_XE_QUERY_CONFIG_FLAGS] & DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY)
devinfo->supports_low_latency_hint = true;
if (config->info[DRM_XE_QUERY_CONFIG_FLAGS] & DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT)
devinfo->xe2_has_no_compression_hint = true;
if (config->info[DRM_XE_QUERY_CONFIG_FLAGS] & DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX)
devinfo->xe_has_state_cache_perf_fix = true;
if (config->info[DRM_XE_QUERY_CONFIG_FLAGS] & DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT)
devinfo->has_madvise_purgeable = true;
if (!has_gmd_ip_version(devinfo))
devinfo->revision = (config->info[DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID] >> 16) & 0xFFFF;
devinfo->gtt_size = 1ull << config->info[DRM_XE_QUERY_CONFIG_VA_BITS];
devinfo->mem_alignment = config->info[DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT];
free(config);
return true;
}
bool
intel_device_info_xe_query_regions(int fd, struct intel_device_info *devinfo,
bool update)
{
struct drm_xe_query_mem_regions *regions;
regions = xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_MEM_REGIONS, NULL);
if (!regions)
return false;
for (int i = 0; i < regions->num_mem_regions; i++) {
struct drm_xe_mem_region *region = &regions->mem_regions[i];
switch (region->mem_class) {
case DRM_XE_MEM_REGION_CLASS_SYSMEM: {
if (!update) {
devinfo->mem.sram.mem.klass = region->mem_class;
devinfo->mem.sram.mem.instance = region->instance;
devinfo->mem.sram.mappable.size = region->total_size;
} else {
assert(devinfo->mem.sram.mem.klass == region->mem_class);
assert(devinfo->mem.sram.mem.instance == region->instance);
assert(devinfo->mem.sram.mappable.size == region->total_size);
}
/* if running without elevated privileges Xe reports used == 0 */
devinfo->mem.sram.mappable.free = region->total_size - region->used;
break;
}
case DRM_XE_MEM_REGION_CLASS_VRAM: {
if (!update) {
devinfo->mem.vram.mem.klass = region->mem_class;
devinfo->mem.vram.mem.instance = region->instance;
devinfo->mem.vram.mappable.size = region->cpu_visible_size;
devinfo->mem.vram.unmappable.size = region->total_size - region->cpu_visible_size;
} else {
assert(devinfo->mem.vram.mem.klass == region->mem_class);
assert(devinfo->mem.vram.mem.instance == region->instance);
assert(devinfo->mem.vram.mappable.size == region->cpu_visible_size);
assert(devinfo->mem.vram.unmappable.size == (region->total_size - region->cpu_visible_size));
}
devinfo->mem.vram.mappable.free = devinfo->mem.vram.mappable.size - region->cpu_visible_used;
devinfo->mem.vram.unmappable.free = devinfo->mem.vram.unmappable.size - (region->used - region->cpu_visible_used);
break;
}
default:
mesa_loge("Unhandled Xe memory class");
break;
}
}
devinfo->mem.use_class_instance = true;
free(regions);
return true;
}
static bool
xe_query_gts(int fd, struct intel_device_info *devinfo)
{
struct drm_xe_query_gt_list *gt_list;
gt_list = xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_GT_LIST, NULL);
if (!gt_list)
return false;
for (uint32_t i = 0; i < gt_list->num_gt; i++) {
if (gt_list->gt_list[i].type == DRM_XE_QUERY_GT_TYPE_MAIN) {
devinfo->timestamp_frequency = gt_list->gt_list[i].reference_clock;
if (has_gmd_ip_version(devinfo)) {
devinfo->gfx_ip_ver = GFX_IP_VER(gt_list->gt_list[i].ip_ver_major,
gt_list->gt_list[i].ip_ver_minor);
devinfo->revision = gt_list->gt_list[i].ip_ver_rev;
}
break;
}
}
free(gt_list);
return true;
}
void *
intel_device_info_xe_query_hwconfig(int fd, int32_t *len)
{
return xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_HWCONFIG, len);
}
static bool
xe_query_process_hwconfig(int fd, struct intel_device_info *devinfo)
{
int32_t len;
void *data = intel_device_info_xe_query_hwconfig(fd, &len);
if (!data)
return false;
bool ret = intel_hwconfig_process_table(devinfo, data, len);
free(data);
return ret;
}
static void
xe_compute_topology(struct intel_device_info * devinfo,
const uint8_t *geo_dss_mask,
const uint32_t geo_dss_num_bytes,
const uint64_t eu_per_dss_mask,
const unsigned l3_banks)
{
intel_device_info_topology_reset_masks(devinfo);
/* TGL/DG1/ADL-P: 1 slice x 6 dual sub slices
* RKL/ADL-S: 1 slice x 2 dual sub slices
* DG2: 8 slices x 4 dual sub slices
*/
if (devinfo->verx10 >= 300) {
/* was set by hwconfig */
} else if (devinfo->verx10 >= 125) {
devinfo->max_slices = 8;
devinfo->max_subslices_per_slice = 4;
} else {
devinfo->max_slices = 1;
devinfo->max_subslices_per_slice = 6;
}
devinfo->max_eus_per_subslice = __builtin_popcount(eu_per_dss_mask);
devinfo->subslice_slice_stride = DIV_ROUND_UP(devinfo->max_slices, 8);
devinfo->eu_slice_stride = DIV_ROUND_UP(devinfo->max_eus_per_subslice * devinfo->max_subslices_per_slice, 8);
devinfo->eu_subslice_stride = DIV_ROUND_UP(devinfo->max_eus_per_subslice, 8);
assert((sizeof(uint32_t) * 8) >= devinfo->max_subslices_per_slice);
assert((sizeof(uint32_t) * 8) >= devinfo->max_eus_per_subslice);
assert(INTEL_DEVICE_MAX_SLICES >= devinfo->max_slices);
assert(INTEL_DEVICE_MAX_SUBSLICES >= devinfo->max_subslices_per_slice);
const uint32_t dss_mask_in_slice = (1u << devinfo->max_subslices_per_slice) - 1;
struct slice {
uint32_t dss_mask;
struct {
bool enabled;
uint64_t eu_mask;
} dual_subslice[INTEL_DEVICE_MAX_SUBSLICES];
} slices[INTEL_DEVICE_MAX_SLICES] = {};
/* Compute and fill slices */
for (unsigned s = 0; s < devinfo->max_slices; s++) {
const unsigned first_bit = s * devinfo->max_subslices_per_slice;
const unsigned dss_index = first_bit / 8;
const unsigned shift = first_bit % 8;
assert(geo_dss_num_bytes > dss_index);
const uint32_t *dss_mask_ptr = (const uint32_t *)&geo_dss_mask[dss_index];
uint32_t dss_mask = *dss_mask_ptr;
dss_mask >>= shift;
dss_mask &= dss_mask_in_slice;
if (dss_mask) {
slices[s].dss_mask = dss_mask;
for (uint32_t dss = 0; dss < devinfo->max_subslices_per_slice; dss++) {
if ((1u << dss) & slices[s].dss_mask) {
slices[s].dual_subslice[dss].enabled = true;
slices[s].dual_subslice[dss].eu_mask = eu_per_dss_mask;
}
}
}
}
/* Set devinfo masks */
for (unsigned s = 0; s < devinfo->max_slices; s++) {
if (!slices[s].dss_mask)
continue;
devinfo->slice_masks |= (1u << s);
for (unsigned ss = 0; ss < devinfo->max_subslices_per_slice; ss++) {
if (!slices[s].dual_subslice[ss].eu_mask)
continue;
devinfo->subslice_masks[s * devinfo->subslice_slice_stride +
ss / 8] |= (1u << (ss % 8));
for (unsigned eu = 0; eu < devinfo->max_eus_per_subslice; eu++) {
if (!(slices[s].dual_subslice[ss].eu_mask & (1ULL << eu)))
continue;
devinfo->eu_masks[s * devinfo->eu_slice_stride +
ss * devinfo->eu_subslice_stride +
eu / 8] |= (1u << (eu % 8));
}
}
}
intel_device_info_topology_update_counts(devinfo);
intel_device_info_update_pixel_pipes(devinfo, devinfo->subslice_masks);
if (devinfo->ver != 12)
devinfo->l3_banks = l3_banks;
else
intel_device_info_update_l3_banks(devinfo);
}
static bool
xe_query_topology(int fd, struct intel_device_info *devinfo)
{
struct drm_xe_query_topology_mask *topology;
int32_t len;
topology = xe_query_alloc_fetch(fd, DRM_XE_DEVICE_QUERY_GT_TOPOLOGY, &len);
if (!topology)
return false;
uint64_t eu_per_dss_mask = 0;
uint32_t geo_dss_num_bytes = 0;
uint8_t *geo_dss_mask = NULL, *tmp;
unsigned l3_banks = 0;
const struct drm_xe_query_topology_mask *head = topology;
tmp = (uint8_t *)topology + len;
const struct drm_xe_query_topology_mask *end = (struct drm_xe_query_topology_mask *)tmp;
while (topology < end) {
if (topology->gt_id == 0) {
switch (topology->type) {
case DRM_XE_TOPO_DSS_GEOMETRY:
geo_dss_mask = topology->mask;
geo_dss_num_bytes = topology->num_bytes;
break;
case DRM_XE_TOPO_L3_BANK:
for (int i = 0; i < topology->num_bytes; i++)
l3_banks += util_bitcount(topology->mask[i]);
break;
case DRM_XE_TOPO_EU_PER_DSS:
case DRM_XE_TOPO_SIMD16_EU_PER_DSS:
assert(topology->num_bytes <= sizeof(eu_per_dss_mask));
for (int i = 0; i < topology->num_bytes; i++)
eu_per_dss_mask |= ((uint64_t)topology->mask[i]) << (8 * i);
break;
}
}
topology = (struct drm_xe_query_topology_mask *)&topology->mask[topology->num_bytes];
}
bool ret = true;
if (!geo_dss_num_bytes || !geo_dss_mask || !eu_per_dss_mask) {
ret = false;
goto parse_failed;
}
xe_compute_topology(devinfo, geo_dss_mask, geo_dss_num_bytes,
eu_per_dss_mask, l3_banks);
parse_failed:
free((void *)head);
return ret;
}
bool
intel_device_info_xe_get_info_from_fd(int fd, struct intel_device_info *devinfo)
{
if (!intel_device_info_xe_query_regions(fd, devinfo, false))
return false;
if (!xe_query_config(fd, devinfo))
return false;
if (!xe_query_gts(fd, devinfo))
return false;
if (!xe_query_process_hwconfig(fd, devinfo))
return false;
/* xe_compute_topology() depends on information provided by hwconfig */
if (!xe_query_topology(fd, devinfo))
return false;
devinfo->has_context_isolation = true;
devinfo->has_mmap_offset = true;
devinfo->has_partial_mmap_offset = true;
devinfo->has_caching_uapi = false;
devinfo->has_set_pat_uapi = true;
devinfo->has_userptr_uapi = true;
return true;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright © 2023 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.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
struct intel_device_info;
bool
intel_device_info_xe_get_info_from_fd(int fd,
struct intel_device_info *devinfo);
bool
intel_device_info_xe_query_regions(int fd, struct intel_device_info *devinfo,
bool update);
void *
intel_device_info_xe_query_hwconfig(int fd, int32_t *len);