mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-10-31 19:08:03 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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")]
|
||||
)
|
||||
Executable
+166
@@ -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
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -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(¶ms, 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(¶ms);
|
||||
out:
|
||||
free(params.out_syncobjs);
|
||||
free(params.in_syncobjs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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 = ®ions->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;
|
||||
}
|
||||
@@ -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);
|
||||
Reference in new issue
Block a user