Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
2cbe1a33
Commit
2cbe1a33
authored
Oct 05, 2023
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge earlier changes in Intel thermal drivers for v6.7.
parents
a56cc0a8
1ced5dce
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
764 additions
and
157 deletions
+764
-157
Documentation/driver-api/thermal/intel_dptf.rst
Documentation/driver-api/thermal/intel_dptf.rst
+54
-0
drivers/thermal/intel/int340x_thermal/Makefile
drivers/thermal/intel/int340x_thermal/Makefile
+2
-0
drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
.../thermal/intel/int340x_thermal/processor_thermal_device.c
+13
-4
drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
.../thermal/intel/int340x_thermal/processor_thermal_device.h
+19
-3
drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
...rmal/intel/int340x_thermal/processor_thermal_device_pci.c
+62
-18
drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c
...tel/int340x_thermal/processor_thermal_device_pci_legacy.c
+2
-1
drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
...rs/thermal/intel/int340x_thermal/processor_thermal_mbox.c
+48
-131
drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c
...thermal/intel/int340x_thermal/processor_thermal_wt_hint.c
+258
-0
drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c
.../thermal/intel/int340x_thermal/processor_thermal_wt_req.c
+136
-0
tools/testing/selftests/Makefile
tools/testing/selftests/Makefile
+1
-0
tools/testing/selftests/thermal/intel/workload_hint/Makefile
tools/testing/selftests/thermal/intel/workload_hint/Makefile
+12
-0
tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c
...elftests/thermal/intel/workload_hint/workload_hint_test.c
+157
-0
No files found.
Documentation/driver-api/thermal/intel_dptf.rst
View file @
2cbe1a33
...
...
@@ -315,3 +315,57 @@ DPTF Fan Control
----------------------------------------
Refer to Documentation/admin-guide/acpi/fan_performance_states.rst
Workload Type Hints
----------------------------------------
The firmware in Meteor Lake processor generation is capable of identifying
workload type and passing hints regarding it to the OS. A special sysfs
interface is provided to allow user space to obtain workload type hints from
the firmware and control the rate at which they are provided.
User space can poll attribute "workload_type_index" for the current hint or
can receive a notification whenever the value of this attribute is updated.
file:`/sys/bus/pci/devices/0000:00:04.0/workload_hint/`
Segment 0, bus 0, device 4, function 0 is reserved for the processor thermal
device on all Intel client processors. So, the above path doesn't change
based on the processor generation.
``workload_hint_enable`` (RW)
Enable firmware to send workload type hints to user space.
``notification_delay_ms`` (RW)
Minimum delay in milliseconds before firmware will notify OS. This is
for the rate control of notifications. This delay is between changing
the workload type prediction in the firmware and notifying the OS about
the change. The default delay is 1024 ms. The delay of 0 is invalid.
The delay is rounded up to the nearest power of 2 to simplify firmware
programming of the delay value. The read of notification_delay_ms
attribute shows the effective value used.
``workload_type_index`` (RO)
Predicted workload type index. User space can get notification of
change via existing sysfs attribute change notification mechanism.
The supported index values and their meaning for the Meteor Lake
processor generation are as follows:
0 - Idle: System performs no tasks, power and idle residency are
consistently low for long periods of time.
1 – Battery Life: Power is relatively low, but the processor may
still be actively performing a task, such as video playback for
a long period of time.
2 – Sustained: Power level that is relatively high for a long period
of time, with very few to no periods of idleness, which will
eventually exhaust RAPL Power Limit 1 and 2.
3 – Bursty: Consumes a relatively constant average amount of power, but
periods of relative idleness are interrupted by bursts of
activity. The bursts are relatively short and the periods of
relative idleness between them typically prevent RAPL Power
Limit 1 from being exhausted.
4 – Unknown: Can't classify.
drivers/thermal/intel/int340x_thermal/Makefile
View file @
2cbe1a33
...
...
@@ -10,5 +10,7 @@ obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.o
obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL)
+=
processor_thermal_rapl.o
obj-$(CONFIG_INT340X_THERMAL)
+=
processor_thermal_rfim.o
obj-$(CONFIG_INT340X_THERMAL)
+=
processor_thermal_mbox.o
obj-$(CONFIG_INT340X_THERMAL)
+=
processor_thermal_wt_req.o
obj-$(CONFIG_INT340X_THERMAL)
+=
processor_thermal_wt_hint.o
obj-$(CONFIG_INT3406_THERMAL)
+=
int3406_thermal.o
obj-$(CONFIG_ACPI_THERMAL_REL)
+=
acpi_thermal_rel.o
drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
View file @
2cbe1a33
...
...
@@ -346,12 +346,18 @@ int proc_thermal_mmio_add(struct pci_dev *pdev,
}
}
if
(
feature_mask
&
PROC_THERMAL_FEATURE_
MBOX
)
{
ret
=
proc_thermal_
mbox
_add
(
pdev
,
proc_priv
);
if
(
feature_mask
&
PROC_THERMAL_FEATURE_
WT_REQ
)
{
ret
=
proc_thermal_
wt_req
_add
(
pdev
,
proc_priv
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to add MBOX interface
\n
"
);
goto
err_rem_rfim
;
}
}
else
if
(
feature_mask
&
PROC_THERMAL_FEATURE_WT_HINT
)
{
ret
=
proc_thermal_wt_hint_add
(
pdev
,
proc_priv
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to add WT Hint
\n
"
);
goto
err_rem_rfim
;
}
}
return
0
;
...
...
@@ -374,12 +380,15 @@ void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *
proc_priv
->
mmio_feature_mask
&
PROC_THERMAL_FEATURE_DVFS
)
proc_thermal_rfim_remove
(
pdev
);
if
(
proc_priv
->
mmio_feature_mask
&
PROC_THERMAL_FEATURE_MBOX
)
proc_thermal_mbox_remove
(
pdev
);
if
(
proc_priv
->
mmio_feature_mask
&
PROC_THERMAL_FEATURE_WT_REQ
)
proc_thermal_wt_req_remove
(
pdev
);
else
if
(
proc_priv
->
mmio_feature_mask
&
PROC_THERMAL_FEATURE_WT_HINT
)
proc_thermal_wt_hint_remove
(
pdev
);
}
EXPORT_SYMBOL_GPL
(
proc_thermal_mmio_remove
);
MODULE_IMPORT_NS
(
INTEL_TCC
);
MODULE_IMPORT_NS
(
INT340X_THERMAL
);
MODULE_AUTHOR
(
"Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"
);
MODULE_DESCRIPTION
(
"Processor Thermal Reporting Device Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
View file @
2cbe1a33
...
...
@@ -10,6 +10,7 @@
#include <linux/intel_rapl.h>
#define PCI_DEVICE_ID_INTEL_ADL_THERMAL 0x461d
#define PCI_DEVICE_ID_INTEL_ARL_S_THERMAL 0xAD03
#define PCI_DEVICE_ID_INTEL_BDW_THERMAL 0x1603
#define PCI_DEVICE_ID_INTEL_BSW_THERMAL 0x22DC
...
...
@@ -59,8 +60,9 @@ struct rapl_mmio_regs {
#define PROC_THERMAL_FEATURE_RAPL 0x01
#define PROC_THERMAL_FEATURE_FIVR 0x02
#define PROC_THERMAL_FEATURE_DVFS 0x04
#define PROC_THERMAL_FEATURE_
MBOX
0x08
#define PROC_THERMAL_FEATURE_
WT_REQ
0x08
#define PROC_THERMAL_FEATURE_DLVR 0x10
#define PROC_THERMAL_FEATURE_WT_HINT 0x20
#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
int
proc_thermal_rapl_add
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
);
...
...
@@ -80,13 +82,27 @@ static void __maybe_unused proc_thermal_rapl_remove(void)
int
proc_thermal_rfim_add
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
);
void
proc_thermal_rfim_remove
(
struct
pci_dev
*
pdev
);
int
proc_thermal_mbox_add
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
);
void
proc_thermal_mbox_remove
(
struct
pci_dev
*
pdev
);
int
proc_thermal_wt_req_add
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
);
void
proc_thermal_wt_req_remove
(
struct
pci_dev
*
pdev
);
#define MBOX_CMD_WORKLOAD_TYPE_READ 0x0E
#define MBOX_CMD_WORKLOAD_TYPE_WRITE 0x0F
#define MBOX_DATA_BIT_AC_DC 30
#define MBOX_DATA_BIT_VALID 31
int
processor_thermal_send_mbox_read_cmd
(
struct
pci_dev
*
pdev
,
u16
id
,
u64
*
resp
);
int
processor_thermal_send_mbox_write_cmd
(
struct
pci_dev
*
pdev
,
u16
id
,
u32
data
);
int
processor_thermal_mbox_interrupt_config
(
struct
pci_dev
*
pdev
,
bool
enable
,
int
enable_bit
,
int
time_window
);
int
proc_thermal_add
(
struct
device
*
dev
,
struct
proc_thermal_device
*
priv
);
void
proc_thermal_remove
(
struct
proc_thermal_device
*
proc_priv
);
int
proc_thermal_wt_hint_add
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
);
void
proc_thermal_wt_hint_remove
(
struct
pci_dev
*
pdev
);
void
proc_thermal_wt_intr_callback
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
);
bool
proc_thermal_check_wt_intr
(
struct
proc_thermal_device
*
proc_priv
);
int
proc_thermal_suspend
(
struct
device
*
dev
);
int
proc_thermal_resume
(
struct
device
*
dev
);
int
proc_thermal_mmio_add
(
struct
pci_dev
*
pdev
,
...
...
drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
View file @
2cbe1a33
...
...
@@ -15,6 +15,11 @@
#define DRV_NAME "proc_thermal_pci"
static
bool
use_msi
;
module_param
(
use_msi
,
bool
,
0644
);
MODULE_PARM_DESC
(
use_msi
,
"Use PCI MSI based interrupts for processor thermal device."
);
struct
proc_thermal_pci
{
struct
pci_dev
*
pdev
;
struct
proc_thermal_device
*
proc_priv
;
...
...
@@ -117,20 +122,44 @@ static void pkg_thermal_schedule_work(struct delayed_work *work)
schedule_delayed_work
(
work
,
ms
);
}
static
irqreturn_t
proc_thermal_irq_thread_handler
(
int
irq
,
void
*
devid
)
{
struct
proc_thermal_pci
*
pci_info
=
devid
;
proc_thermal_wt_intr_callback
(
pci_info
->
pdev
,
pci_info
->
proc_priv
);
return
IRQ_HANDLED
;
}
static
irqreturn_t
proc_thermal_irq_handler
(
int
irq
,
void
*
devid
)
{
struct
proc_thermal_pci
*
pci_info
=
devid
;
struct
proc_thermal_device
*
proc_priv
;
int
ret
=
IRQ_HANDLED
;
u32
status
;
proc_
thermal_mmio_read
(
pci_info
,
PROC_THERMAL_MMIO_INT_STATUS_0
,
&
status
)
;
proc_
priv
=
pci_info
->
proc_priv
;
if
(
proc_priv
->
mmio_feature_mask
&
PROC_THERMAL_FEATURE_WT_HINT
)
{
if
(
proc_thermal_check_wt_intr
(
pci_info
->
proc_priv
))
ret
=
IRQ_WAKE_THREAD
;
}
/*
* Since now there are two sources of interrupts: one from thermal threshold
* and another from workload hint, add a check if there was really a threshold
* interrupt before scheduling work function for thermal threshold.
*/
proc_thermal_mmio_read
(
pci_info
,
PROC_THERMAL_MMIO_INT_STATUS_0
,
&
status
);
if
(
status
)
{
/* Disable enable interrupt flag */
proc_thermal_mmio_write
(
pci_info
,
PROC_THERMAL_MMIO_INT_ENABLE_0
,
0
);
pci_write_config_byte
(
pci_info
->
pdev
,
0xdc
,
0x01
);
pkg_thermal_schedule_work
(
&
pci_info
->
work
);
}
return
IRQ_HANDLED
;
pci_write_config_byte
(
pci_info
->
pdev
,
0xdc
,
0x01
);
return
ret
;
}
static
int
sys_get_curr_temp
(
struct
thermal_zone_device
*
tzd
,
int
*
temp
)
...
...
@@ -203,6 +232,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
struct
proc_thermal_device
*
proc_priv
;
struct
proc_thermal_pci
*
pci_info
;
int
irq_flag
=
0
,
irq
,
ret
;
bool
msi_irq
=
false
;
proc_priv
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
proc_priv
),
GFP_KERNEL
);
if
(
!
proc_priv
)
...
...
@@ -248,18 +278,23 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
goto
err_ret_mmio
;
}
if
(
use_msi
&&
(
pdev
->
msi_enabled
||
pdev
->
msix_enabled
))
{
/* request and enable interrupt */
ret
=
pci_alloc_irq_vectors
(
pdev
,
1
,
1
,
PCI_IRQ_ALL_TYPES
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to allocate vectors!
\n
"
);
goto
err_ret_tzone
;
}
if
(
!
pdev
->
msi_enabled
&&
!
pdev
->
msix_enabled
)
irq_flag
=
IRQF_SHARED
;
irq
=
pci_irq_vector
(
pdev
,
0
);
msi_irq
=
true
;
}
else
{
irq_flag
=
IRQF_SHARED
;
irq
=
pdev
->
irq
;
}
ret
=
devm_request_threaded_irq
(
&
pdev
->
dev
,
irq
,
proc_thermal_irq_handler
,
NULL
,
proc_thermal_irq_handler
,
proc_thermal_irq_thread_handler
,
irq_flag
,
KBUILD_MODNAME
,
pci_info
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Request IRQ %d failed
\n
"
,
pdev
->
irq
);
...
...
@@ -273,6 +308,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
return
0
;
err_free_vectors:
if
(
msi_irq
)
pci_free_irq_vectors
(
pdev
);
err_ret_tzone:
thermal_zone_device_unregister
(
pci_info
->
tzone
);
...
...
@@ -350,9 +386,15 @@ static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
proc_thermal_pci_resume
);
static
const
struct
pci_device_id
proc_thermal_pci_ids
[]
=
{
{
PCI_DEVICE_DATA
(
INTEL
,
ADL_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_FIVR
|
PROC_THERMAL_FEATURE_DVFS
|
PROC_THERMAL_FEATURE_MBOX
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
MTLP_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_FIVR
|
PROC_THERMAL_FEATURE_DVFS
|
PROC_THERMAL_FEATURE_MBOX
|
PROC_THERMAL_FEATURE_DLVR
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
RPL_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_FIVR
|
PROC_THERMAL_FEATURE_DVFS
|
PROC_THERMAL_FEATURE_MBOX
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
ADL_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_FIVR
|
PROC_THERMAL_FEATURE_DVFS
|
PROC_THERMAL_FEATURE_WT_REQ
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
MTLP_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_FIVR
|
PROC_THERMAL_FEATURE_DVFS
|
PROC_THERMAL_FEATURE_DLVR
|
PROC_THERMAL_FEATURE_WT_HINT
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
ARL_S_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_DVFS
|
PROC_THERMAL_FEATURE_DLVR
|
PROC_THERMAL_FEATURE_WT_HINT
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
RPL_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_FIVR
|
PROC_THERMAL_FEATURE_DVFS
|
PROC_THERMAL_FEATURE_WT_REQ
)
},
{
},
};
...
...
@@ -368,6 +410,8 @@ static struct pci_driver proc_thermal_pci_driver = {
module_pci_driver
(
proc_thermal_pci_driver
);
MODULE_IMPORT_NS
(
INT340X_THERMAL
);
MODULE_AUTHOR
(
"Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"
);
MODULE_DESCRIPTION
(
"Processor Thermal Reporting Device Driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c
View file @
2cbe1a33
...
...
@@ -137,7 +137,8 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
{
PCI_DEVICE_DATA
(
INTEL
,
ICL_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
JSL_THERMAL
,
0
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
SKL_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
TGL_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_FIVR
|
PROC_THERMAL_FEATURE_MBOX
)
},
{
PCI_DEVICE_DATA
(
INTEL
,
TGL_THERMAL
,
PROC_THERMAL_FEATURE_RAPL
|
PROC_THERMAL_FEATURE_FIVR
|
PROC_THERMAL_FEATURE_WT_REQ
)
},
{
},
};
...
...
drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
View file @
2cbe1a33
...
...
@@ -10,18 +10,12 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include "processor_thermal_device.h"
#define MBOX_CMD_WORKLOAD_TYPE_READ 0x0E
#define MBOX_CMD_WORKLOAD_TYPE_WRITE 0x0F
#define MBOX_OFFSET_DATA 0x5810
#define MBOX_OFFSET_INTERFACE 0x5818
#define MBOX_BUSY_BIT 31
#define MBOX_RETRY_COUNT 100
#define MBOX_DATA_BIT_VALID 31
#define MBOX_DATA_BIT_AC_DC 30
static
DEFINE_MUTEX
(
mbox_lock
);
static
int
wait_for_mbox_ready
(
struct
proc_thermal_device
*
proc_priv
)
...
...
@@ -51,23 +45,16 @@ static int send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
int
ret
;
proc_priv
=
pci_get_drvdata
(
pdev
);
mutex_lock
(
&
mbox_lock
);
ret
=
wait_for_mbox_ready
(
proc_priv
);
if
(
ret
)
goto
unlock_mbox
;
return
ret
;
writel
(
data
,
(
proc_priv
->
mmio_base
+
MBOX_OFFSET_DATA
));
/* Write command register */
reg_data
=
BIT_ULL
(
MBOX_BUSY_BIT
)
|
id
;
writel
(
reg_data
,
(
proc_priv
->
mmio_base
+
MBOX_OFFSET_INTERFACE
));
ret
=
wait_for_mbox_ready
(
proc_priv
);
unlock_mbox:
mutex_unlock
(
&
mbox_lock
);
return
ret
;
return
wait_for_mbox_ready
(
proc_priv
);
}
static
int
send_mbox_read_cmd
(
struct
pci_dev
*
pdev
,
u16
id
,
u64
*
resp
)
...
...
@@ -77,12 +64,9 @@ static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
int
ret
;
proc_priv
=
pci_get_drvdata
(
pdev
);
mutex_lock
(
&
mbox_lock
);
ret
=
wait_for_mbox_ready
(
proc_priv
);
if
(
ret
)
goto
unlock_mbox
;
return
ret
;
/* Write command register */
reg_data
=
BIT_ULL
(
MBOX_BUSY_BIT
)
|
id
;
...
...
@@ -90,152 +74,85 @@ static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
ret
=
wait_for_mbox_ready
(
proc_priv
);
if
(
ret
)
goto
unlock_mbox
;
return
ret
;
if
(
id
==
MBOX_CMD_WORKLOAD_TYPE_READ
)
*
resp
=
readl
(
proc_priv
->
mmio_base
+
MBOX_OFFSET_DATA
);
else
*
resp
=
readq
(
proc_priv
->
mmio_base
+
MBOX_OFFSET_DATA
);
unlock_mbox:
mutex_unlock
(
&
mbox_lock
);
return
ret
;
return
0
;
}
int
processor_thermal_send_mbox_read_cmd
(
struct
pci_dev
*
pdev
,
u16
id
,
u64
*
resp
)
{
return
send_mbox_read_cmd
(
pdev
,
id
,
resp
);
}
EXPORT_SYMBOL_NS_GPL
(
processor_thermal_send_mbox_read_cmd
,
INT340X_THERMAL
);
int
processor_thermal_send_mbox_write_cmd
(
struct
pci_dev
*
pdev
,
u16
id
,
u32
data
)
{
return
send_mbox_write_cmd
(
pdev
,
id
,
data
);
}
EXPORT_SYMBOL_NS_GPL
(
processor_thermal_send_mbox_write_cmd
,
INT340X_THERMAL
);
/* List of workload types */
static
const
char
*
const
workload_types
[]
=
{
"none"
,
"idle"
,
"semi_active"
,
"bursty"
,
"sustained"
,
"battery_life"
,
NULL
};
static
ssize_t
workload_available_types_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
int
i
=
0
;
int
ret
=
0
;
while
(
workload_types
[
i
]
!=
NULL
)
ret
+=
sprintf
(
&
buf
[
ret
],
"%s "
,
workload_types
[
i
++
]);
int
ret
;
ret
+=
sprintf
(
&
buf
[
ret
],
"
\n
"
);
mutex_lock
(
&
mbox_lock
);
ret
=
send_mbox_read_cmd
(
pdev
,
id
,
resp
);
mutex_unlock
(
&
mbox_lock
);
return
ret
;
}
EXPORT_SYMBOL_NS_GPL
(
processor_thermal_send_mbox_read_cmd
,
INT340X_THERMAL
);
static
DEVICE_ATTR_RO
(
workload_available_types
);
static
ssize_t
workload_type_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
int
processor_thermal_send_mbox_write_cmd
(
struct
pci_dev
*
pdev
,
u16
id
,
u32
data
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
char
str_preference
[
15
];
u32
data
=
0
;
ssize_t
ret
;
int
ret
;
ret
=
sscanf
(
buf
,
"%14s"
,
str_preference
);
if
(
ret
!=
1
)
return
-
EINVAL
;
mutex_lock
(
&
mbox_lock
);
ret
=
send_mbox_write_cmd
(
pdev
,
id
,
data
);
mutex_unlock
(
&
mbox_lock
)
;
ret
=
match_string
(
workload_types
,
-
1
,
str_preference
);
if
(
ret
<
0
)
return
ret
;
ret
&=
0xff
;
if
(
ret
)
data
=
BIT
(
MBOX_DATA_BIT_VALID
)
|
BIT
(
MBOX_DATA_BIT_AC_DC
);
data
|=
ret
;
ret
=
send_mbox_write_cmd
(
pdev
,
MBOX_CMD_WORKLOAD_TYPE_WRITE
,
data
);
if
(
ret
)
return
false
;
return
count
;
}
EXPORT_SYMBOL_NS_GPL
(
processor_thermal_send_mbox_write_cmd
,
INT340X_THERMAL
);
static
ssize_t
workload_type_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
#define MBOX_CAMARILLO_RD_INTR_CONFIG 0x1E
#define MBOX_CAMARILLO_WR_INTR_CONFIG 0x1F
#define WLT_TW_MASK GENMASK_ULL(30, 24)
#define SOC_PREDICTION_TW_SHIFT 24
int
processor_thermal_mbox_interrupt_config
(
struct
pci_dev
*
pdev
,
bool
enable
,
int
enable_bit
,
int
time_window
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
u64
cmd_resp
;
u64
data
;
int
ret
;
ret
=
send_mbox_read_cmd
(
pdev
,
MBOX_CMD_WORKLOAD_TYPE_READ
,
&
cmd_resp
);
if
(
ret
)
return
false
;
cmd_resp
&=
0xff
;
if
(
cmd_resp
>
ARRAY_SIZE
(
workload_types
)
-
1
)
return
-
EINVAL
;
return
sprintf
(
buf
,
"%s
\n
"
,
workload_types
[
cmd_resp
]);
}
if
(
!
pdev
)
return
-
ENODEV
;
static
DEVICE_ATTR_RW
(
workload_type
);
mutex_lock
(
&
mbox_lock
);
static
struct
attribute
*
workload_req_attrs
[]
=
{
&
dev_attr_workload_available_types
.
attr
,
&
dev_attr_workload_type
.
attr
,
NULL
};
/* Do read modify write for MBOX_CAMARILLO_RD_INTR_CONFIG */
static
const
struct
attribute_group
workload_req_attribute_group
=
{
.
attrs
=
workload_req_attrs
,
.
name
=
"workload_request"
};
ret
=
send_mbox_read_cmd
(
pdev
,
MBOX_CAMARILLO_RD_INTR_CONFIG
,
&
data
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"MBOX_CAMARILLO_RD_INTR_CONFIG failed
\n
"
);
goto
unlock
;
}
static
bool
workload_req_created
;
if
(
time_window
>=
0
)
{
data
&=
~
WLT_TW_MASK
;
int
proc_thermal_mbox_add
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
)
{
u64
cmd_resp
;
int
ret
;
/* Program notification delay */
data
|=
((
u64
)
time_window
<<
SOC_PREDICTION_TW_SHIFT
)
&
WLT_TW_MASK
;
}
/* Check if there is a mailbox support, if fails return success */
ret
=
send_mbox_read_cmd
(
pdev
,
MBOX_CMD_WORKLOAD_TYPE_READ
,
&
cmd_resp
);
if
(
ret
)
return
0
;
if
(
enable
)
data
|=
BIT
(
enable_bit
);
else
data
&=
~
BIT
(
enable_bit
)
;
ret
=
s
ysfs_create_group
(
&
pdev
->
dev
.
kobj
,
&
workload_req_attribute_group
);
ret
=
s
end_mbox_write_cmd
(
pdev
,
MBOX_CAMARILLO_WR_INTR_CONFIG
,
data
);
if
(
ret
)
return
ret
;
dev_err
(
&
pdev
->
dev
,
"MBOX_CAMARILLO_WR_INTR_CONFIG failed
\n
"
)
;
workload_req_created
=
true
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
proc_thermal_mbox_add
);
void
proc_thermal_mbox_remove
(
struct
pci_dev
*
pdev
)
{
if
(
workload_req_created
)
sysfs_remove_group
(
&
pdev
->
dev
.
kobj
,
&
workload_req_attribute_group
);
workload_req_created
=
false
;
unlock:
mutex_unlock
(
&
mbox_lock
);
return
ret
;
}
EXPORT_SYMBOL_
GPL
(
proc_thermal_mbox_remove
);
EXPORT_SYMBOL_
NS_GPL
(
processor_thermal_mbox_interrupt_config
,
INT340X_THERMAL
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c
0 → 100644
View file @
2cbe1a33
// SPDX-License-Identifier: GPL-2.0-only
/*
* processor thermal device interface for reading workload type hints
* from the user space. The hints are provided by the firmware.
*
* Operation:
* When user space enables workload type prediction:
* - Use mailbox to:
* Configure notification delay
* Enable processor thermal device interrupt
*
* - The predicted workload type can be read from MMIO:
* Offset 0x5B18 shows if there was an interrupt
* active for change in workload type and also
* predicted workload type.
*
* Two interface functions are provided to call when there is a
* thermal device interrupt:
* - proc_thermal_check_wt_intr():
* Check if the interrupt is for change in workload type. Called from
* interrupt context.
*
* - proc_thermal_wt_intr_callback():
* Callback for interrupt processing in thread context. This involves
* sending notification to user space that there is a change in the
* workload type.
*
* Copyright (c) 2023, Intel Corporation.
*/
#include <linux/bitfield.h>
#include <linux/pci.h>
#include "processor_thermal_device.h"
#define SOC_WT_RES_INT_STATUS_OFFSET 0x5B18
#define SOC_WT GENMASK_ULL(47, 40)
#define SOC_WT_PREDICTION_INT_ENABLE_BIT 23
#define SOC_WT_PREDICTION_INT_ACTIVE BIT(2)
/*
* Closest possible to 1 Second is 1024 ms with programmed time delay
* of 0x0A.
*/
static
u8
notify_delay
=
0x0A
;
static
u16
notify_delay_ms
=
1024
;
static
DEFINE_MUTEX
(
wt_lock
);
static
u8
wt_enable
;
/* Show current predicted workload type index */
static
ssize_t
workload_type_index_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
proc_thermal_device
*
proc_priv
;
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
u64
status
=
0
;
int
wt
;
mutex_lock
(
&
wt_lock
);
if
(
!
wt_enable
)
{
mutex_unlock
(
&
wt_lock
);
return
-
ENODATA
;
}
proc_priv
=
pci_get_drvdata
(
pdev
);
status
=
readq
(
proc_priv
->
mmio_base
+
SOC_WT_RES_INT_STATUS_OFFSET
);
mutex_unlock
(
&
wt_lock
);
wt
=
FIELD_GET
(
SOC_WT
,
status
);
return
sysfs_emit
(
buf
,
"%d
\n
"
,
wt
);
}
static
DEVICE_ATTR_RO
(
workload_type_index
);
static
ssize_t
workload_hint_enable_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
return
sysfs_emit
(
buf
,
"%d
\n
"
,
wt_enable
);
}
static
ssize_t
workload_hint_enable_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
size
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
u8
mode
;
int
ret
;
if
(
kstrtou8
(
buf
,
10
,
&
mode
)
||
mode
>
1
)
return
-
EINVAL
;
mutex_lock
(
&
wt_lock
);
if
(
mode
)
ret
=
processor_thermal_mbox_interrupt_config
(
pdev
,
true
,
SOC_WT_PREDICTION_INT_ENABLE_BIT
,
notify_delay
);
else
ret
=
processor_thermal_mbox_interrupt_config
(
pdev
,
false
,
SOC_WT_PREDICTION_INT_ENABLE_BIT
,
0
);
if
(
ret
)
goto
ret_enable_store
;
ret
=
size
;
wt_enable
=
mode
;
ret_enable_store:
mutex_unlock
(
&
wt_lock
);
return
ret
;
}
static
DEVICE_ATTR_RW
(
workload_hint_enable
);
static
ssize_t
notification_delay_ms_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
return
sysfs_emit
(
buf
,
"%u
\n
"
,
notify_delay_ms
);
}
static
ssize_t
notification_delay_ms_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
size
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
u16
new_tw
;
int
ret
;
u8
tm
;
/*
* Time window register value:
* Formula: (1 + x/4) * power(2,y)
* x = 2 msbs, that is [30:29] y = 5 [28:24]
* in INTR_CONFIG register.
* The result will be in milli seconds.
* Here, just keep x = 0, and just change y.
* First round up the user value to power of 2 and
* then take log2, to get "y" value to program.
*/
ret
=
kstrtou16
(
buf
,
10
,
&
new_tw
);
if
(
ret
)
return
ret
;
if
(
!
new_tw
)
return
-
EINVAL
;
new_tw
=
roundup_pow_of_two
(
new_tw
);
tm
=
ilog2
(
new_tw
);
if
(
tm
>
31
)
return
-
EINVAL
;
mutex_lock
(
&
wt_lock
);
/* If the workload hint was already enabled, then update with the new delay */
if
(
wt_enable
)
ret
=
processor_thermal_mbox_interrupt_config
(
pdev
,
true
,
SOC_WT_PREDICTION_INT_ENABLE_BIT
,
tm
);
if
(
!
ret
)
{
ret
=
size
;
notify_delay
=
tm
;
notify_delay_ms
=
new_tw
;
}
mutex_unlock
(
&
wt_lock
);
return
ret
;
}
static
DEVICE_ATTR_RW
(
notification_delay_ms
);
static
struct
attribute
*
workload_hint_attrs
[]
=
{
&
dev_attr_workload_type_index
.
attr
,
&
dev_attr_workload_hint_enable
.
attr
,
&
dev_attr_notification_delay_ms
.
attr
,
NULL
};
static
const
struct
attribute_group
workload_hint_attribute_group
=
{
.
attrs
=
workload_hint_attrs
,
.
name
=
"workload_hint"
};
/*
* Callback to check if the interrupt for prediction is active.
* Caution: Called from the interrupt context.
*/
bool
proc_thermal_check_wt_intr
(
struct
proc_thermal_device
*
proc_priv
)
{
u64
int_status
;
int_status
=
readq
(
proc_priv
->
mmio_base
+
SOC_WT_RES_INT_STATUS_OFFSET
);
if
(
int_status
&
SOC_WT_PREDICTION_INT_ACTIVE
)
return
true
;
return
false
;
}
EXPORT_SYMBOL_NS_GPL
(
proc_thermal_check_wt_intr
,
INT340X_THERMAL
);
/* Callback to notify user space */
void
proc_thermal_wt_intr_callback
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
)
{
u64
status
;
status
=
readq
(
proc_priv
->
mmio_base
+
SOC_WT_RES_INT_STATUS_OFFSET
);
if
(
!
(
status
&
SOC_WT_PREDICTION_INT_ACTIVE
))
return
;
writeq
(
status
&
~
SOC_WT_PREDICTION_INT_ACTIVE
,
proc_priv
->
mmio_base
+
SOC_WT_RES_INT_STATUS_OFFSET
);
sysfs_notify
(
&
pdev
->
dev
.
kobj
,
"workload_hint"
,
"workload_type_index"
);
}
EXPORT_SYMBOL_NS_GPL
(
proc_thermal_wt_intr_callback
,
INT340X_THERMAL
);
static
bool
workload_hint_created
;
int
proc_thermal_wt_hint_add
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
)
{
int
ret
;
ret
=
sysfs_create_group
(
&
pdev
->
dev
.
kobj
,
&
workload_hint_attribute_group
);
if
(
ret
)
return
ret
;
workload_hint_created
=
true
;
return
0
;
}
EXPORT_SYMBOL_NS_GPL
(
proc_thermal_wt_hint_add
,
INT340X_THERMAL
);
void
proc_thermal_wt_hint_remove
(
struct
pci_dev
*
pdev
)
{
mutex_lock
(
&
wt_lock
);
if
(
wt_enable
)
processor_thermal_mbox_interrupt_config
(
pdev
,
false
,
SOC_WT_PREDICTION_INT_ENABLE_BIT
,
0
);
mutex_unlock
(
&
wt_lock
);
if
(
workload_hint_created
)
sysfs_remove_group
(
&
pdev
->
dev
.
kobj
,
&
workload_hint_attribute_group
);
workload_hint_created
=
false
;
}
EXPORT_SYMBOL_NS_GPL
(
proc_thermal_wt_hint_remove
,
INT340X_THERMAL
);
MODULE_IMPORT_NS
(
INT340X_THERMAL
);
MODULE_LICENSE
(
"GPL"
);
drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c
0 → 100644
View file @
2cbe1a33
// SPDX-License-Identifier: GPL-2.0-only
/*
* processor thermal device for Workload type hints
* update from user space
*
* Copyright (c) 2020-2023, Intel Corporation.
*/
#include <linux/pci.h>
#include "processor_thermal_device.h"
/* List of workload types */
static
const
char
*
const
workload_types
[]
=
{
"none"
,
"idle"
,
"semi_active"
,
"bursty"
,
"sustained"
,
"battery_life"
,
NULL
};
static
ssize_t
workload_available_types_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
int
i
=
0
;
int
ret
=
0
;
while
(
workload_types
[
i
]
!=
NULL
)
ret
+=
sprintf
(
&
buf
[
ret
],
"%s "
,
workload_types
[
i
++
]);
ret
+=
sprintf
(
&
buf
[
ret
],
"
\n
"
);
return
ret
;
}
static
DEVICE_ATTR_RO
(
workload_available_types
);
static
ssize_t
workload_type_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
char
str_preference
[
15
];
u32
data
=
0
;
ssize_t
ret
;
ret
=
sscanf
(
buf
,
"%14s"
,
str_preference
);
if
(
ret
!=
1
)
return
-
EINVAL
;
ret
=
match_string
(
workload_types
,
-
1
,
str_preference
);
if
(
ret
<
0
)
return
ret
;
ret
&=
0xff
;
if
(
ret
)
data
=
BIT
(
MBOX_DATA_BIT_VALID
)
|
BIT
(
MBOX_DATA_BIT_AC_DC
);
data
|=
ret
;
ret
=
processor_thermal_send_mbox_write_cmd
(
pdev
,
MBOX_CMD_WORKLOAD_TYPE_WRITE
,
data
);
if
(
ret
)
return
false
;
return
count
;
}
static
ssize_t
workload_type_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
u64
cmd_resp
;
int
ret
;
ret
=
processor_thermal_send_mbox_read_cmd
(
pdev
,
MBOX_CMD_WORKLOAD_TYPE_READ
,
&
cmd_resp
);
if
(
ret
)
return
false
;
cmd_resp
&=
0xff
;
if
(
cmd_resp
>
ARRAY_SIZE
(
workload_types
)
-
1
)
return
-
EINVAL
;
return
sprintf
(
buf
,
"%s
\n
"
,
workload_types
[
cmd_resp
]);
}
static
DEVICE_ATTR_RW
(
workload_type
);
static
struct
attribute
*
workload_req_attrs
[]
=
{
&
dev_attr_workload_available_types
.
attr
,
&
dev_attr_workload_type
.
attr
,
NULL
};
static
const
struct
attribute_group
workload_req_attribute_group
=
{
.
attrs
=
workload_req_attrs
,
.
name
=
"workload_request"
};
static
bool
workload_req_created
;
int
proc_thermal_wt_req_add
(
struct
pci_dev
*
pdev
,
struct
proc_thermal_device
*
proc_priv
)
{
u64
cmd_resp
;
int
ret
;
/* Check if there is a mailbox support, if fails return success */
ret
=
processor_thermal_send_mbox_read_cmd
(
pdev
,
MBOX_CMD_WORKLOAD_TYPE_READ
,
&
cmd_resp
);
if
(
ret
)
return
0
;
ret
=
sysfs_create_group
(
&
pdev
->
dev
.
kobj
,
&
workload_req_attribute_group
);
if
(
ret
)
return
ret
;
workload_req_created
=
true
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
proc_thermal_wt_req_add
);
void
proc_thermal_wt_req_remove
(
struct
pci_dev
*
pdev
)
{
if
(
workload_req_created
)
sysfs_remove_group
(
&
pdev
->
dev
.
kobj
,
&
workload_req_attribute_group
);
workload_req_created
=
false
;
}
EXPORT_SYMBOL_GPL
(
proc_thermal_wt_req_remove
);
MODULE_IMPORT_NS
(
INT340X_THERMAL
);
MODULE_LICENSE
(
"GPL"
);
tools/testing/selftests/Makefile
View file @
2cbe1a33
...
...
@@ -85,6 +85,7 @@ TARGETS += syscall_user_dispatch
TARGETS
+=
sysctl
TARGETS
+=
tc-testing
TARGETS
+=
tdx
TARGETS
+=
thermal/intel/workload_hint
TARGETS
+=
timens
ifneq
(1, $(quicktest))
TARGETS
+=
timers
...
...
tools/testing/selftests/thermal/intel/workload_hint/Makefile
0 → 100644
View file @
2cbe1a33
# SPDX-License-Identifier: GPL-2.0
ifndef
CROSS_COMPILE
uname_M
:=
$(
shell
uname
-m
2>/dev/null
||
echo
not
)
ARCH
?=
$(
shell
echo
$(uname_M)
|
sed
-e
s/i.86/x86/
-e
s/x86_64/x86/
)
ifeq
($(ARCH),x86)
TEST_GEN_PROGS
:=
workload_hint_test
include
../../../lib.mk
endif
endif
tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c
0 → 100644
View file @
2cbe1a33
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#define WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/notification_delay_ms"
#define WORKLOAD_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_hint_enable"
#define WORKLOAD_TYPE_INDEX_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_type_index"
static
const
char
*
const
workload_types
[]
=
{
"idle"
,
"battery_life"
,
"sustained"
,
"bursty"
,
NULL
};
#define WORKLOAD_TYPE_MAX_INDEX 3
void
workload_hint_exit
(
int
signum
)
{
int
fd
;
/* Disable feature via sysfs knob */
fd
=
open
(
WORKLOAD_ENABLE_ATTRIBUTE
,
O_RDWR
);
if
(
fd
<
0
)
{
perror
(
"Unable to open workload type feature enable file
\n
"
);
exit
(
1
);
}
if
(
write
(
fd
,
"0
\n
"
,
2
)
<
0
)
{
perror
(
"Can' disable workload hints
\n
"
);
exit
(
1
);
}
printf
(
"Disabled workload type prediction
\n
"
);
close
(
fd
);
}
int
main
(
int
argc
,
char
**
argv
)
{
struct
pollfd
ufd
;
char
index_str
[
4
];
int
fd
,
ret
,
index
;
char
delay_str
[
64
];
int
delay
=
0
;
printf
(
"Usage: workload_hint_test [notification delay in milli seconds]
\n
"
);
if
(
argc
>
1
)
{
ret
=
sscanf
(
argv
[
1
],
"%d"
,
&
delay
);
if
(
ret
<
0
)
{
printf
(
"Invalid delay
\n
"
);
exit
(
1
);
}
printf
(
"Setting notification delay to %d ms
\n
"
,
delay
);
if
(
delay
<
0
)
exit
(
1
);
sprintf
(
delay_str
,
"%s
\n
"
,
argv
[
1
]);
sprintf
(
delay_str
,
"%s
\n
"
,
argv
[
1
]);
fd
=
open
(
WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE
,
O_RDWR
);
if
(
fd
<
0
)
{
perror
(
"Unable to open workload notification delay
\n
"
);
exit
(
1
);
}
if
(
write
(
fd
,
delay_str
,
strlen
(
delay_str
))
<
0
)
{
perror
(
"Can't set delay
\n
"
);
exit
(
1
);
}
close
(
fd
);
}
if
(
signal
(
SIGINT
,
workload_hint_exit
)
==
SIG_IGN
)
signal
(
SIGINT
,
SIG_IGN
);
if
(
signal
(
SIGHUP
,
workload_hint_exit
)
==
SIG_IGN
)
signal
(
SIGHUP
,
SIG_IGN
);
if
(
signal
(
SIGTERM
,
workload_hint_exit
)
==
SIG_IGN
)
signal
(
SIGTERM
,
SIG_IGN
);
/* Enable feature via sysfs knob */
fd
=
open
(
WORKLOAD_ENABLE_ATTRIBUTE
,
O_RDWR
);
if
(
fd
<
0
)
{
perror
(
"Unable to open workload type feature enable file
\n
"
);
exit
(
1
);
}
if
(
write
(
fd
,
"1
\n
"
,
2
)
<
0
)
{
perror
(
"Can' enable workload hints
\n
"
);
exit
(
1
);
}
close
(
fd
);
printf
(
"Enabled workload type prediction
\n
"
);
while
(
1
)
{
fd
=
open
(
WORKLOAD_TYPE_INDEX_ATTRIBUTE
,
O_RDONLY
);
if
(
fd
<
0
)
{
perror
(
"Unable to open workload type file
\n
"
);
exit
(
1
);
}
if
((
lseek
(
fd
,
0L
,
SEEK_SET
))
<
0
)
{
fprintf
(
stderr
,
"Failed to set pointer to beginning
\n
"
);
exit
(
1
);
}
if
(
read
(
fd
,
index_str
,
sizeof
(
index_str
))
<
0
)
{
fprintf
(
stderr
,
"Failed to read from:%s
\n
"
,
WORKLOAD_TYPE_INDEX_ATTRIBUTE
);
exit
(
1
);
}
ufd
.
fd
=
fd
;
ufd
.
events
=
POLLPRI
;
ret
=
poll
(
&
ufd
,
1
,
-
1
);
if
(
ret
<
0
)
{
perror
(
"poll error"
);
exit
(
1
);
}
else
if
(
ret
==
0
)
{
printf
(
"Poll Timeout
\n
"
);
}
else
{
if
((
lseek
(
fd
,
0L
,
SEEK_SET
))
<
0
)
{
fprintf
(
stderr
,
"Failed to set pointer to beginning
\n
"
);
exit
(
1
);
}
if
(
read
(
fd
,
index_str
,
sizeof
(
index_str
))
<
0
)
exit
(
0
);
ret
=
sscanf
(
index_str
,
"%d"
,
&
index
);
if
(
ret
<
0
)
break
;
if
(
index
>
WORKLOAD_TYPE_MAX_INDEX
)
printf
(
"Invalid workload type index
\n
"
);
else
printf
(
"workload type:%s
\n
"
,
workload_types
[
index
]);
}
close
(
fd
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment