mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-31 14:13:39 +00:00

When an attribute group is created with sysfs_create_group() or sysfs_create_files() the ->sysfs_ops() callback is set to kobj_sysfs_ops, which sets the ->show() callback to kobj_attr_show(). kobj_attr_show() uses container_of() to get the ->show() callback from the attribute it was passed, meaning the ->show() callback needs to be the same type as the ->show() callback in 'struct kobj_attribute'. However, cur_freq_show() has the type of the ->show() callback in 'struct device_attribute', which causes a CFI violation when opening the 'id' sysfs node under gtidle/freq/throttle. This happens to work because the layout of 'struct kobj_attribute' and 'struct device_attribute' are the same, so the container_of() cast happens to allow the ->show() callback to still work. Changed the type of cur_freq_show() and few more functions to match the ->show() callback in 'struct kobj_attributes' to resolve the CFI violation. CFI failure seen while accessing sysfs files under /sys/class/drm/card0/device/tile0/gt*/gtidle/* /sys/class/drm/card0/device/tile0/gt*/freq0/* /sys/class/drm/card0/device/tile0/gt*/freq0/throttle/* [ 2599.618075] RIP: 0010:__cfi_cur_freq_show+0xd/0x10 [xe] [ 2599.624452] Code: 44 c1 44 89 fa e8 03 95 39 f2 48 98 5b 41 5e 41 5f 5d c3 c9 [ 2599.646638] RSP: 0018:ffffbe438ead7d10 EFLAGS: 00010286 [ 2599.652823] RAX: ffff9f7d8b3845d8 RBX: ffff9f7dee8c95d8 RCX: 0000000000000000 [ 2599.661246] RDX: ffff9f7e6f439000 RSI: ffffffffc13ada30 RDI: ffff9f7d975d4b00 [ 2599.669669] RBP: ffffbe438ead7d18 R08: 0000000000001000 R09: ffff9f7e6f439000 [ 2599.678092] R10: 00000000e07304a6 R11: ffffffffc1241ca0 R12: ffffffffb4836ea0 [ 2599.688435] R13: ffff9f7e45fb1180 R14: ffff9f7d975d4b00 R15: ffff9f7e6f439000 [ 2599.696860] FS: 000076b02b66cfc0(0000) GS:ffff9f80ef400000(0000) knlGS:00000 [ 2599.706412] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2599.713196] CR2: 00005f80d94641a9 CR3: 00000001e44ec006 CR4: 0000000100f72ef0 [ 2599.721618] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 2599.730041] DR3: 0000000000000000 DR6: 00000000ffff07f0 DR7: 0000000000000400 [ 2599.738464] PKRU: 55555554 [ 2599.741655] Call Trace: [ 2599.744541] <TASK> [ 2599.747017] ? __die_body+0x69/0xb0 [ 2599.751151] ? die+0xa9/0xd0 [ 2599.754548] ? do_trap+0x89/0x160 [ 2599.758476] ? __cfi_cur_freq_show+0xd/0x10 [xe b37985c94829727668bd7c5b33c1] [ 2599.768315] ? handle_invalid_op+0x69/0x90 [ 2599.773167] ? __cfi_cur_freq_show+0xd/0x10 [xe b37985c94829727668bd7c5b33c1] [ 2599.783010] ? exc_invalid_op+0x36/0x60 [ 2599.787552] ? fred_hwexc+0x123/0x1a0 [ 2599.791873] ? fred_entry_from_kernel+0x7b/0xd0 [ 2599.797219] ? asm_fred_entrypoint_kernel+0x45/0x70 [ 2599.802976] ? act_freq_show+0x70/0x70 [xe b37985c94829727668bd7c5b33c1d9998] [ 2599.812301] ? __cfi_cur_freq_show+0xd/0x10 [xe b37985c94829727668bd7c5b33c1] [ 2599.822137] ? __kmalloc_node_noprof+0x1f3/0x420 [ 2599.827594] ? __kvmalloc_node_noprof+0xcb/0x180 [ 2599.833045] ? kobj_attr_show+0x22/0x40 [ 2599.837571] sysfs_kf_seq_show+0xa8/0x110 [ 2599.842302] kernfs_seq_show+0x38/0x50 Signed-off-by: Jeevaka Prabu Badrappan <jeevaka.badrappan@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://lore.kernel.org/r/20250422171852.85558-1-jeevaka.badrappan@intel.com Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
252 lines
6.5 KiB
C
252 lines
6.5 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2023 Intel Corporation
|
|
*/
|
|
|
|
#include <drm/drm_managed.h>
|
|
|
|
#include <regs/xe_gt_regs.h>
|
|
#include "xe_device.h"
|
|
#include "xe_gt.h"
|
|
#include "xe_gt_printk.h"
|
|
#include "xe_gt_sysfs.h"
|
|
#include "xe_gt_throttle.h"
|
|
#include "xe_mmio.h"
|
|
#include "xe_pm.h"
|
|
|
|
/**
|
|
* DOC: Xe GT Throttle
|
|
*
|
|
* Provides sysfs entries and other helpers for frequency throttle reasons in GT
|
|
*
|
|
* device/gt#/freq0/throttle/status - Overall status
|
|
* device/gt#/freq0/throttle/reason_pl1 - Frequency throttle due to PL1
|
|
* device/gt#/freq0/throttle/reason_pl2 - Frequency throttle due to PL2
|
|
* device/gt#/freq0/throttle/reason_pl4 - Frequency throttle due to PL4, Iccmax etc.
|
|
* device/gt#/freq0/throttle/reason_thermal - Frequency throttle due to thermal
|
|
* device/gt#/freq0/throttle/reason_prochot - Frequency throttle due to prochot
|
|
* device/gt#/freq0/throttle/reason_ratl - Frequency throttle due to RATL
|
|
* device/gt#/freq0/throttle/reason_vr_thermalert - Frequency throttle due to VR THERMALERT
|
|
* device/gt#/freq0/throttle/reason_vr_tdc - Frequency throttle due to VR TDC
|
|
*/
|
|
|
|
static struct xe_gt *
|
|
dev_to_gt(struct device *dev)
|
|
{
|
|
return kobj_to_gt(dev->kobj.parent);
|
|
}
|
|
|
|
u32 xe_gt_throttle_get_limit_reasons(struct xe_gt *gt)
|
|
{
|
|
u32 reg;
|
|
|
|
xe_pm_runtime_get(gt_to_xe(gt));
|
|
if (xe_gt_is_media_type(gt))
|
|
reg = xe_mmio_read32(>->mmio, MTL_MEDIA_PERF_LIMIT_REASONS);
|
|
else
|
|
reg = xe_mmio_read32(>->mmio, GT0_PERF_LIMIT_REASONS);
|
|
xe_pm_runtime_put(gt_to_xe(gt));
|
|
|
|
return reg;
|
|
}
|
|
|
|
static u32 read_status(struct xe_gt *gt)
|
|
{
|
|
u32 status = xe_gt_throttle_get_limit_reasons(gt) & GT0_PERF_LIMIT_REASONS_MASK;
|
|
|
|
xe_gt_dbg(gt, "throttle reasons: 0x%08x\n", status);
|
|
return status;
|
|
}
|
|
|
|
static u32 read_reason_pl1(struct xe_gt *gt)
|
|
{
|
|
u32 pl1 = xe_gt_throttle_get_limit_reasons(gt) & POWER_LIMIT_1_MASK;
|
|
|
|
return pl1;
|
|
}
|
|
|
|
static u32 read_reason_pl2(struct xe_gt *gt)
|
|
{
|
|
u32 pl2 = xe_gt_throttle_get_limit_reasons(gt) & POWER_LIMIT_2_MASK;
|
|
|
|
return pl2;
|
|
}
|
|
|
|
static u32 read_reason_pl4(struct xe_gt *gt)
|
|
{
|
|
u32 pl4 = xe_gt_throttle_get_limit_reasons(gt) & POWER_LIMIT_4_MASK;
|
|
|
|
return pl4;
|
|
}
|
|
|
|
static u32 read_reason_thermal(struct xe_gt *gt)
|
|
{
|
|
u32 thermal = xe_gt_throttle_get_limit_reasons(gt) & THERMAL_LIMIT_MASK;
|
|
|
|
return thermal;
|
|
}
|
|
|
|
static u32 read_reason_prochot(struct xe_gt *gt)
|
|
{
|
|
u32 prochot = xe_gt_throttle_get_limit_reasons(gt) & PROCHOT_MASK;
|
|
|
|
return prochot;
|
|
}
|
|
|
|
static u32 read_reason_ratl(struct xe_gt *gt)
|
|
{
|
|
u32 ratl = xe_gt_throttle_get_limit_reasons(gt) & RATL_MASK;
|
|
|
|
return ratl;
|
|
}
|
|
|
|
static u32 read_reason_vr_thermalert(struct xe_gt *gt)
|
|
{
|
|
u32 thermalert = xe_gt_throttle_get_limit_reasons(gt) & VR_THERMALERT_MASK;
|
|
|
|
return thermalert;
|
|
}
|
|
|
|
static u32 read_reason_vr_tdc(struct xe_gt *gt)
|
|
{
|
|
u32 tdc = xe_gt_throttle_get_limit_reasons(gt) & VR_TDC_MASK;
|
|
|
|
return tdc;
|
|
}
|
|
|
|
static ssize_t status_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool status = !!read_status(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", status);
|
|
}
|
|
static struct kobj_attribute attr_status = __ATTR_RO(status);
|
|
|
|
static ssize_t reason_pl1_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool pl1 = !!read_reason_pl1(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", pl1);
|
|
}
|
|
static struct kobj_attribute attr_reason_pl1 = __ATTR_RO(reason_pl1);
|
|
|
|
static ssize_t reason_pl2_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool pl2 = !!read_reason_pl2(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", pl2);
|
|
}
|
|
static struct kobj_attribute attr_reason_pl2 = __ATTR_RO(reason_pl2);
|
|
|
|
static ssize_t reason_pl4_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool pl4 = !!read_reason_pl4(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", pl4);
|
|
}
|
|
static struct kobj_attribute attr_reason_pl4 = __ATTR_RO(reason_pl4);
|
|
|
|
static ssize_t reason_thermal_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool thermal = !!read_reason_thermal(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", thermal);
|
|
}
|
|
static struct kobj_attribute attr_reason_thermal = __ATTR_RO(reason_thermal);
|
|
|
|
static ssize_t reason_prochot_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool prochot = !!read_reason_prochot(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", prochot);
|
|
}
|
|
static struct kobj_attribute attr_reason_prochot = __ATTR_RO(reason_prochot);
|
|
|
|
static ssize_t reason_ratl_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool ratl = !!read_reason_ratl(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", ratl);
|
|
}
|
|
static struct kobj_attribute attr_reason_ratl = __ATTR_RO(reason_ratl);
|
|
|
|
static ssize_t reason_vr_thermalert_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool thermalert = !!read_reason_vr_thermalert(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", thermalert);
|
|
}
|
|
static struct kobj_attribute attr_reason_vr_thermalert = __ATTR_RO(reason_vr_thermalert);
|
|
|
|
static ssize_t reason_vr_tdc_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buff)
|
|
{
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
struct xe_gt *gt = dev_to_gt(dev);
|
|
bool tdc = !!read_reason_vr_tdc(gt);
|
|
|
|
return sysfs_emit(buff, "%u\n", tdc);
|
|
}
|
|
static struct kobj_attribute attr_reason_vr_tdc = __ATTR_RO(reason_vr_tdc);
|
|
|
|
static struct attribute *throttle_attrs[] = {
|
|
&attr_status.attr,
|
|
&attr_reason_pl1.attr,
|
|
&attr_reason_pl2.attr,
|
|
&attr_reason_pl4.attr,
|
|
&attr_reason_thermal.attr,
|
|
&attr_reason_prochot.attr,
|
|
&attr_reason_ratl.attr,
|
|
&attr_reason_vr_thermalert.attr,
|
|
&attr_reason_vr_tdc.attr,
|
|
NULL
|
|
};
|
|
|
|
static const struct attribute_group throttle_group_attrs = {
|
|
.name = "throttle",
|
|
.attrs = throttle_attrs,
|
|
};
|
|
|
|
static void gt_throttle_sysfs_fini(void *arg)
|
|
{
|
|
struct xe_gt *gt = arg;
|
|
|
|
sysfs_remove_group(gt->freq, &throttle_group_attrs);
|
|
}
|
|
|
|
int xe_gt_throttle_init(struct xe_gt *gt)
|
|
{
|
|
struct xe_device *xe = gt_to_xe(gt);
|
|
int err;
|
|
|
|
err = sysfs_create_group(gt->freq, &throttle_group_attrs);
|
|
if (err)
|
|
return err;
|
|
|
|
return devm_add_action_or_reset(xe->drm.dev, gt_throttle_sysfs_fini, gt);
|
|
}
|