drm/xe/oa: Move functions up so they can be reused for config ioctl
[ Upstream commit cc4e6994d5a237ef38363e459ac83cf8ef7626ff ] No code changes, only code movement so that functions used during stream open can be reused for the stream reconfiguration ioctl (DRM_XE_OBSERVATION_IOCTL_CONFIG). Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com> Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20241022200352.1192560-6-ashutosh.dixit@intel.com Stable-dep-of: 5bd566703e16 ("drm/xe/oa: Allow oa_exponent value of 0") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
5fe916b2c9
commit
fa41f3cd4e
+229
-229
@@ -1091,6 +1091,235 @@ static int xe_oa_enable_metric_set(struct xe_oa_stream *stream)
|
||||
return xe_oa_emit_oa_config(stream, stream->oa_config);
|
||||
}
|
||||
|
||||
static int decode_oa_format(struct xe_oa *oa, u64 fmt, enum xe_oa_format_name *name)
|
||||
{
|
||||
u32 counter_size = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SIZE, fmt);
|
||||
u32 counter_sel = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SEL, fmt);
|
||||
u32 bc_report = FIELD_GET(DRM_XE_OA_FORMAT_MASK_BC_REPORT, fmt);
|
||||
u32 type = FIELD_GET(DRM_XE_OA_FORMAT_MASK_FMT_TYPE, fmt);
|
||||
int idx;
|
||||
|
||||
for_each_set_bit(idx, oa->format_mask, __XE_OA_FORMAT_MAX) {
|
||||
const struct xe_oa_format *f = &oa->oa_formats[idx];
|
||||
|
||||
if (counter_size == f->counter_size && bc_report == f->bc_report &&
|
||||
type == f->type && counter_sel == f->counter_select) {
|
||||
*name = idx;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_unit_id(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
if (value >= oa->oa_unit_ids) {
|
||||
drm_dbg(&oa->xe->drm, "OA unit ID out of range %lld\n", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
param->oa_unit_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_sample_oa(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->sample = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_metric_set(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->metric_set = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_format(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
int ret = decode_oa_format(oa, value, ¶m->oa_format);
|
||||
|
||||
if (ret) {
|
||||
drm_dbg(&oa->xe->drm, "Unsupported OA report format %#llx\n", value);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_exponent(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
#define OA_EXPONENT_MAX 31
|
||||
|
||||
if (value > OA_EXPONENT_MAX) {
|
||||
drm_dbg(&oa->xe->drm, "OA timer exponent too high (> %u)\n", OA_EXPONENT_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
param->period_exponent = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_disabled(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->disabled = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_exec_queue_id(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->exec_queue_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_engine_instance(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->engine_instance = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_no_preempt(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->no_preempt = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_num_syncs(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->num_syncs = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_syncs_user(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->syncs_user = u64_to_user_ptr(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*xe_oa_set_property_fn)(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param);
|
||||
static const xe_oa_set_property_fn xe_oa_set_property_funcs[] = {
|
||||
[DRM_XE_OA_PROPERTY_OA_UNIT_ID] = xe_oa_set_prop_oa_unit_id,
|
||||
[DRM_XE_OA_PROPERTY_SAMPLE_OA] = xe_oa_set_prop_sample_oa,
|
||||
[DRM_XE_OA_PROPERTY_OA_METRIC_SET] = xe_oa_set_prop_metric_set,
|
||||
[DRM_XE_OA_PROPERTY_OA_FORMAT] = xe_oa_set_prop_oa_format,
|
||||
[DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT] = xe_oa_set_prop_oa_exponent,
|
||||
[DRM_XE_OA_PROPERTY_OA_DISABLED] = xe_oa_set_prop_disabled,
|
||||
[DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID] = xe_oa_set_prop_exec_queue_id,
|
||||
[DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE] = xe_oa_set_prop_engine_instance,
|
||||
[DRM_XE_OA_PROPERTY_NO_PREEMPT] = xe_oa_set_no_preempt,
|
||||
[DRM_XE_OA_PROPERTY_NUM_SYNCS] = xe_oa_set_prop_num_syncs,
|
||||
[DRM_XE_OA_PROPERTY_SYNCS] = xe_oa_set_prop_syncs_user,
|
||||
};
|
||||
|
||||
static int xe_oa_user_ext_set_property(struct xe_oa *oa, u64 extension,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
u64 __user *address = u64_to_user_ptr(extension);
|
||||
struct drm_xe_ext_set_property ext;
|
||||
int err;
|
||||
u32 idx;
|
||||
|
||||
err = __copy_from_user(&ext, address, sizeof(ext));
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return -EFAULT;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext.property >= ARRAY_SIZE(xe_oa_set_property_funcs)) ||
|
||||
XE_IOCTL_DBG(oa->xe, ext.pad))
|
||||
return -EINVAL;
|
||||
|
||||
idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_oa_set_property_funcs));
|
||||
return xe_oa_set_property_funcs[idx](oa, ext.value, param);
|
||||
}
|
||||
|
||||
typedef int (*xe_oa_user_extension_fn)(struct xe_oa *oa, u64 extension,
|
||||
struct xe_oa_open_param *param);
|
||||
static const xe_oa_user_extension_fn xe_oa_user_extension_funcs[] = {
|
||||
[DRM_XE_OA_EXTENSION_SET_PROPERTY] = xe_oa_user_ext_set_property,
|
||||
};
|
||||
|
||||
#define MAX_USER_EXTENSIONS 16
|
||||
static int xe_oa_user_extensions(struct xe_oa *oa, u64 extension, int ext_number,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
u64 __user *address = u64_to_user_ptr(extension);
|
||||
struct drm_xe_user_extension ext;
|
||||
int err;
|
||||
u32 idx;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext_number >= MAX_USER_EXTENSIONS))
|
||||
return -E2BIG;
|
||||
|
||||
err = __copy_from_user(&ext, address, sizeof(ext));
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return -EFAULT;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext.pad) ||
|
||||
XE_IOCTL_DBG(oa->xe, ext.name >= ARRAY_SIZE(xe_oa_user_extension_funcs)))
|
||||
return -EINVAL;
|
||||
|
||||
idx = array_index_nospec(ext.name, ARRAY_SIZE(xe_oa_user_extension_funcs));
|
||||
err = xe_oa_user_extension_funcs[idx](oa, extension, param);
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return err;
|
||||
|
||||
if (ext.next_extension)
|
||||
return xe_oa_user_extensions(oa, ext.next_extension, ++ext_number, param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_parse_syncs(struct xe_oa *oa, struct xe_oa_open_param *param)
|
||||
{
|
||||
int ret, num_syncs, num_ufence = 0;
|
||||
|
||||
if (param->num_syncs && !param->syncs_user) {
|
||||
drm_dbg(&oa->xe->drm, "num_syncs specified without sync array\n");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (param->num_syncs) {
|
||||
param->syncs = kcalloc(param->num_syncs, sizeof(*param->syncs), GFP_KERNEL);
|
||||
if (!param->syncs) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
for (num_syncs = 0; num_syncs < param->num_syncs; num_syncs++) {
|
||||
ret = xe_sync_entry_parse(oa->xe, param->xef, ¶m->syncs[num_syncs],
|
||||
¶m->syncs_user[num_syncs], 0);
|
||||
if (ret)
|
||||
goto err_syncs;
|
||||
|
||||
if (xe_sync_is_ufence(¶m->syncs[num_syncs]))
|
||||
num_ufence++;
|
||||
}
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, num_ufence > 1)) {
|
||||
ret = -EINVAL;
|
||||
goto err_syncs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_syncs:
|
||||
while (num_syncs--)
|
||||
xe_sync_entry_cleanup(¶m->syncs[num_syncs]);
|
||||
kfree(param->syncs);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xe_oa_stream_enable(struct xe_oa_stream *stream)
|
||||
{
|
||||
stream->pollin = false;
|
||||
@@ -1664,27 +1893,6 @@ static bool engine_supports_oa_format(const struct xe_hw_engine *hwe, int type)
|
||||
}
|
||||
}
|
||||
|
||||
static int decode_oa_format(struct xe_oa *oa, u64 fmt, enum xe_oa_format_name *name)
|
||||
{
|
||||
u32 counter_size = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SIZE, fmt);
|
||||
u32 counter_sel = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SEL, fmt);
|
||||
u32 bc_report = FIELD_GET(DRM_XE_OA_FORMAT_MASK_BC_REPORT, fmt);
|
||||
u32 type = FIELD_GET(DRM_XE_OA_FORMAT_MASK_FMT_TYPE, fmt);
|
||||
int idx;
|
||||
|
||||
for_each_set_bit(idx, oa->format_mask, __XE_OA_FORMAT_MAX) {
|
||||
const struct xe_oa_format *f = &oa->oa_formats[idx];
|
||||
|
||||
if (counter_size == f->counter_size && bc_report == f->bc_report &&
|
||||
type == f->type && counter_sel == f->counter_select) {
|
||||
*name = idx;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_oa_unit_id - Return OA unit ID for a hardware engine
|
||||
* @hwe: @xe_hw_engine
|
||||
@@ -1731,214 +1939,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_unit_id(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
if (value >= oa->oa_unit_ids) {
|
||||
drm_dbg(&oa->xe->drm, "OA unit ID out of range %lld\n", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
param->oa_unit_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_sample_oa(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->sample = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_metric_set(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->metric_set = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_format(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
int ret = decode_oa_format(oa, value, ¶m->oa_format);
|
||||
|
||||
if (ret) {
|
||||
drm_dbg(&oa->xe->drm, "Unsupported OA report format %#llx\n", value);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_oa_exponent(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
#define OA_EXPONENT_MAX 31
|
||||
|
||||
if (value > OA_EXPONENT_MAX) {
|
||||
drm_dbg(&oa->xe->drm, "OA timer exponent too high (> %u)\n", OA_EXPONENT_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
param->period_exponent = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_disabled(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->disabled = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_exec_queue_id(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->exec_queue_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_engine_instance(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->engine_instance = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_no_preempt(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->no_preempt = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_num_syncs(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->num_syncs = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_set_prop_syncs_user(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
param->syncs_user = u64_to_user_ptr(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*xe_oa_set_property_fn)(struct xe_oa *oa, u64 value,
|
||||
struct xe_oa_open_param *param);
|
||||
static const xe_oa_set_property_fn xe_oa_set_property_funcs[] = {
|
||||
[DRM_XE_OA_PROPERTY_OA_UNIT_ID] = xe_oa_set_prop_oa_unit_id,
|
||||
[DRM_XE_OA_PROPERTY_SAMPLE_OA] = xe_oa_set_prop_sample_oa,
|
||||
[DRM_XE_OA_PROPERTY_OA_METRIC_SET] = xe_oa_set_prop_metric_set,
|
||||
[DRM_XE_OA_PROPERTY_OA_FORMAT] = xe_oa_set_prop_oa_format,
|
||||
[DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT] = xe_oa_set_prop_oa_exponent,
|
||||
[DRM_XE_OA_PROPERTY_OA_DISABLED] = xe_oa_set_prop_disabled,
|
||||
[DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID] = xe_oa_set_prop_exec_queue_id,
|
||||
[DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE] = xe_oa_set_prop_engine_instance,
|
||||
[DRM_XE_OA_PROPERTY_NO_PREEMPT] = xe_oa_set_no_preempt,
|
||||
[DRM_XE_OA_PROPERTY_NUM_SYNCS] = xe_oa_set_prop_num_syncs,
|
||||
[DRM_XE_OA_PROPERTY_SYNCS] = xe_oa_set_prop_syncs_user,
|
||||
};
|
||||
|
||||
static int xe_oa_user_ext_set_property(struct xe_oa *oa, u64 extension,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
u64 __user *address = u64_to_user_ptr(extension);
|
||||
struct drm_xe_ext_set_property ext;
|
||||
int err;
|
||||
u32 idx;
|
||||
|
||||
err = __copy_from_user(&ext, address, sizeof(ext));
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return -EFAULT;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext.property >= ARRAY_SIZE(xe_oa_set_property_funcs)) ||
|
||||
XE_IOCTL_DBG(oa->xe, ext.pad))
|
||||
return -EINVAL;
|
||||
|
||||
idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_oa_set_property_funcs));
|
||||
return xe_oa_set_property_funcs[idx](oa, ext.value, param);
|
||||
}
|
||||
|
||||
typedef int (*xe_oa_user_extension_fn)(struct xe_oa *oa, u64 extension,
|
||||
struct xe_oa_open_param *param);
|
||||
static const xe_oa_user_extension_fn xe_oa_user_extension_funcs[] = {
|
||||
[DRM_XE_OA_EXTENSION_SET_PROPERTY] = xe_oa_user_ext_set_property,
|
||||
};
|
||||
|
||||
#define MAX_USER_EXTENSIONS 16
|
||||
static int xe_oa_user_extensions(struct xe_oa *oa, u64 extension, int ext_number,
|
||||
struct xe_oa_open_param *param)
|
||||
{
|
||||
u64 __user *address = u64_to_user_ptr(extension);
|
||||
struct drm_xe_user_extension ext;
|
||||
int err;
|
||||
u32 idx;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext_number >= MAX_USER_EXTENSIONS))
|
||||
return -E2BIG;
|
||||
|
||||
err = __copy_from_user(&ext, address, sizeof(ext));
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return -EFAULT;
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, ext.pad) ||
|
||||
XE_IOCTL_DBG(oa->xe, ext.name >= ARRAY_SIZE(xe_oa_user_extension_funcs)))
|
||||
return -EINVAL;
|
||||
|
||||
idx = array_index_nospec(ext.name, ARRAY_SIZE(xe_oa_user_extension_funcs));
|
||||
err = xe_oa_user_extension_funcs[idx](oa, extension, param);
|
||||
if (XE_IOCTL_DBG(oa->xe, err))
|
||||
return err;
|
||||
|
||||
if (ext.next_extension)
|
||||
return xe_oa_user_extensions(oa, ext.next_extension, ++ext_number, param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xe_oa_parse_syncs(struct xe_oa *oa, struct xe_oa_open_param *param)
|
||||
{
|
||||
int ret, num_syncs, num_ufence = 0;
|
||||
|
||||
if (param->num_syncs && !param->syncs_user) {
|
||||
drm_dbg(&oa->xe->drm, "num_syncs specified without sync array\n");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (param->num_syncs) {
|
||||
param->syncs = kcalloc(param->num_syncs, sizeof(*param->syncs), GFP_KERNEL);
|
||||
if (!param->syncs) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
for (num_syncs = 0; num_syncs < param->num_syncs; num_syncs++) {
|
||||
ret = xe_sync_entry_parse(oa->xe, param->xef, ¶m->syncs[num_syncs],
|
||||
¶m->syncs_user[num_syncs], 0);
|
||||
if (ret)
|
||||
goto err_syncs;
|
||||
|
||||
if (xe_sync_is_ufence(¶m->syncs[num_syncs]))
|
||||
num_ufence++;
|
||||
}
|
||||
|
||||
if (XE_IOCTL_DBG(oa->xe, num_ufence > 1)) {
|
||||
ret = -EINVAL;
|
||||
goto err_syncs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_syncs:
|
||||
while (num_syncs--)
|
||||
xe_sync_entry_cleanup(¶m->syncs[num_syncs]);
|
||||
kfree(param->syncs);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_oa_stream_open_ioctl - Opens an OA stream
|
||||
* @dev: @drm_device
|
||||
|
||||
Reference in New Issue
Block a user