mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
platform-drivers-x86 for v6.7-1
Highlights: - asus-wmi: Support for screenpad and solve brightness key press duplication - int3472: Eliminate the last use of deprecated GPIO functions - mlxbf-pmc: New HW support - msi-ec: Support new EC configurations - thinkpad_acpi: Support reading aux MAC address during passthrough - wmi: Fixes & improvements - x86-android-tablets: Detection fix and avoid use of GPIO private APIs - Debug & metrics interface improvements - Miscellaneous cleanups / fixes / improvements The following is an automated shortlog grouped by driver: acer-wmi: - Remove void function return amd/hsmp: - add support for metrics tbl - create plat specific struct - Fix iomem handling - improve the error log amd/pmc: - Add dump_custom_stb module parameter - Add PMFW command id to support S2D force flush - Handle overflow cases where the num_samples range is higher - Use flex array when calling amd_pmc_stb_debugfs_open_v2() asus-wireless: - Replace open coded acpi_match_acpi_device() asus-wmi: - add support for ASUS screenpad - Do not report brightness up/down keys when also reported by acpi_video gpiolib: acpi: - Add a ignore interrupt quirk for Peaq C1010 - Check if a GPIO is listed in ignore_interrupt earlier hp-bioscfg: - Annotate struct bios_args with __counted_by inspur-platform-profile: - Add platform profile support int3472: - Add new skl_int3472_fill_gpiod_lookup() helper - Add new skl_int3472_gpiod_get_from_temp_lookup() helper - Stop using gpiod_toggle_active_low() - Switch to devm_get_gpiod() intel: bytcrc_pwrsrc: - Convert to platform remove callback returning void intel/ifs: - Add new CPU support - Add new error code - ARRAY BIST for Sierra Forest - Gen2 scan image loading - Gen2 Scan test support - Metadata validation for start_chunk - Refactor image loading code - Store IFS generation number - Validate image size intel_speed_select_if: - Remove hardcoded map size - Use devm_ioremap_resource intel/tpmi: - Add debugfs support for read/write blocked - Add defines to get version information intel-uncore-freq: - Ignore minor version change ISST: - Allow level 0 to be not present - Ignore minor version change - Use fuse enabled mask instead of allowed levels mellanox: - Fix misspelling error in routine name - Rename some init()/exit() functions for consistent naming mlxbf-bootctl: - Convert to platform remove callback returning void mlxbf-pmc: - Add support for BlueField-3 mlxbf-tmfifo: - Convert to platform remove callback returning void mlx-Convert to platform remove callback returning void: - mlx-Convert to platform remove callback returning void mlxreg-hotplug: - Convert to platform remove callback returning void mlxreg-io: - Convert to platform remove callback returning void mlxreg-lc: - Convert to platform remove callback returning void msi-ec: - Add more EC configs - rename fn_super_swap nvsw-sn2201: - Convert to platform remove callback returning void sel3350-Convert to platform remove callback returning void: - sel3350-Convert to platform remove callback returning void siemens: simatic-ipc-batt-apollolake: - Convert to platform remove callback returning void siemens: simatic-ipc-batt: - Convert to platform remove callback returning void siemens: simatic-ipc-batt-elkhartlake: - Convert to platform remove callback returning void siemens: simatic-ipc-batt-f7188x: - Convert to platform remove callback returning void siemens: simatic-ipc-batt: - Simplify simatic_ipc_batt_remove() surface: acpi-notify: - Convert to platform remove callback returning void surface: aggregator: - Annotate struct ssam_event with __counted_by surface: aggregator-cdev: - Convert to platform remove callback returning void surface: aggregator-registry: - Convert to platform remove callback returning void surface: dtx: - Convert to platform remove callback returning void surface: gpe: - Convert to platform remove callback returning void surface: hotplug: - Convert to platform remove callback returning void surface: surface3-wmi: - Convert to platform remove callback returning void think-lmi: - Add bulk save feature - Replace kstrdup() + strreplace() with kstrdup_and_replace() - Use strreplace() to replace a character by nul thinkpad_acpi: - Add battery quirk for Thinkpad X120e - replace deprecated strncpy with memcpy - sysfs interface to auxmac tools/power/x86/intel-speed-select: - Display error for core-power support - Increase max CPUs in one request - No TRL for non compute domains - Sanitize integer arguments - turbo-mode enable disable swapped - Update help for TRL - Use cgroup isolate for CPU 0 - v1.18 release wmi: - Decouple probe deferring from wmi_block_list - Decouple WMI device removal from wmi_block_list - Fix opening of char device - Fix probe failure when failing to register WMI devices - Fix refcounting of WMI devices in legacy functions x86-android-tablets: - Add a comment about x86_android_tablet_get_gpiod() - Create a platform_device from module_init() - Drop "linux,power-supply-name" from lenovo_yt3_bq25892_0_props[] - Fix Lenovo Yoga Tablet 2 830F/L vs 1050F/L detection - Remove invalid_aei_gpiochip from Peaq C1010 - Remove invalid_aei_gpiochip support - Stop using gpiolib private APIs - Use platform-device as gpio-keys parent xo15-ebook: - Replace open coded acpi_match_acpi_device() Merges: - Merge branch 'pdx86/platform-drivers-x86-int3472' into review-ilpo - Merge branch 'pdx86/platform-drivers-x86-mellanox-init' into review-ilpo - Merge remote-tracking branch 'intel-speed-select/intel-sst' into review-ilpo - Merge remote-tracking branch 'pdx86/platform-drivers-x86-android-tablets' into review-hans -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQSCSUwRdwTNL2MhaBlZrE9hU+XOMQUCZT+lBwAKCRBZrE9hU+XO Mck0AQCFU7dYLCF4d1CXtHf1eZhSXLpYdhcO+C08JGGoM+MqSgD+Jyb9KJHk4pxE FvKG51I9neyAne9lvNrLodHRzxCYgAo= =duM8 -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-v6.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86 Pull x86 platform driver updates from Ilpo Järvinen: - asus-wmi: Support for screenpad and solve brightness key press duplication - int3472: Eliminate the last use of deprecated GPIO functions - mlxbf-pmc: New HW support - msi-ec: Support new EC configurations - thinkpad_acpi: Support reading aux MAC address during passthrough - wmi: Fixes & improvements - x86-android-tablets: Detection fix and avoid use of GPIO private APIs - Debug & metrics interface improvements - Miscellaneous cleanups / fixes / improvements * tag 'platform-drivers-x86-v6.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (80 commits) platform/x86: inspur-platform-profile: Add platform profile support platform/x86: thinkpad_acpi: Add battery quirk for Thinkpad X120e platform/x86: wmi: Decouple WMI device removal from wmi_block_list platform/x86: wmi: Fix opening of char device platform/x86: wmi: Fix probe failure when failing to register WMI devices platform/x86: wmi: Fix refcounting of WMI devices in legacy functions platform/x86: wmi: Decouple probe deferring from wmi_block_list platform/x86/amd/hsmp: Fix iomem handling platform/x86: asus-wmi: Do not report brightness up/down keys when also reported by acpi_video platform/x86: thinkpad_acpi: replace deprecated strncpy with memcpy tools/power/x86/intel-speed-select: v1.18 release tools/power/x86/intel-speed-select: Use cgroup isolate for CPU 0 tools/power/x86/intel-speed-select: Increase max CPUs in one request tools/power/x86/intel-speed-select: Display error for core-power support tools/power/x86/intel-speed-select: No TRL for non compute domains tools/power/x86/intel-speed-select: turbo-mode enable disable swapped tools/power/x86/intel-speed-select: Update help for TRL tools/power/x86/intel-speed-select: Sanitize integer arguments platform/x86: acer-wmi: Remove void function return platform/x86/amd/pmc: Add dump_custom_stb module parameter ...
This commit is contained in:
commit
59fff63cc2
@ -383,6 +383,36 @@ Description:
|
||||
Note that any changes to this attribute requires a reboot
|
||||
for changes to take effect.
|
||||
|
||||
What: /sys/class/firmware-attributes/*/attributes/save_settings
|
||||
Date: August 2023
|
||||
KernelVersion: 6.6
|
||||
Contact: Mark Pearson <mpearson-lenovo@squebb.ca>
|
||||
Description:
|
||||
On Lenovo platforms there is a limitation in the number of times an attribute can be
|
||||
saved. This is an architectural limitation and it limits the number of attributes
|
||||
that can be modified to 48.
|
||||
A solution for this is instead of the attribute being saved after every modification,
|
||||
to allow a user to bulk set the attributes, and then trigger a final save. This allows
|
||||
unlimited attributes.
|
||||
|
||||
Read the attribute to check what save mode is enabled (single or bulk).
|
||||
E.g:
|
||||
# cat /sys/class/firmware-attributes/thinklmi/attributes/save_settings
|
||||
single
|
||||
|
||||
Write the attribute with 'bulk' to enable bulk save mode.
|
||||
Write the attribute with 'single' to enable saving, after every attribute set.
|
||||
The default setting is single mode.
|
||||
E.g:
|
||||
# echo bulk > /sys/class/firmware-attributes/thinklmi/attributes/save_settings
|
||||
|
||||
When in bulk mode write 'save' to trigger a save of all currently modified attributes.
|
||||
Note, once a save has been triggered, in bulk mode, attributes can no longer be set and
|
||||
will return a permissions error. This is to prevent users hitting the 48+ save limitation
|
||||
(which requires entering the BIOS to clear the error condition)
|
||||
E.g:
|
||||
# echo save > /sys/class/firmware-attributes/thinklmi/attributes/save_settings
|
||||
|
||||
What: /sys/class/firmware-attributes/*/attributes/debug_cmd
|
||||
Date: July 2021
|
||||
KernelVersion: 5.14
|
||||
|
@ -53,6 +53,7 @@ detailed description):
|
||||
- Lap mode sensor
|
||||
- Setting keyboard language
|
||||
- WWAN Antenna type
|
||||
- Auxmac
|
||||
|
||||
A compatibility table by model and feature is maintained on the web
|
||||
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
|
||||
@ -1511,6 +1512,25 @@ Currently 2 antenna types are supported as mentioned below:
|
||||
The property is read-only. If the platform doesn't have support the sysfs
|
||||
class is not created.
|
||||
|
||||
Auxmac
|
||||
------
|
||||
|
||||
sysfs: auxmac
|
||||
|
||||
Some newer Thinkpads have a feature called MAC Address Pass-through. This
|
||||
feature is implemented by the system firmware to provide a system unique MAC,
|
||||
that can override a dock or USB ethernet dongle MAC, when connected to a
|
||||
network. This property enables user-space to easily determine the MAC address
|
||||
if the feature is enabled.
|
||||
|
||||
The values of this auxiliary MAC are:
|
||||
|
||||
cat /sys/devices/platform/thinkpad_acpi/auxmac
|
||||
|
||||
If the feature is disabled, the value will be 'disabled'.
|
||||
|
||||
This property is read-only.
|
||||
|
||||
Adaptive keyboard
|
||||
-----------------
|
||||
|
||||
|
@ -41,6 +41,24 @@ In-kernel integration:
|
||||
* Locking across callers is taken care by the driver.
|
||||
|
||||
|
||||
HSMP sysfs interface
|
||||
====================
|
||||
|
||||
1. Metrics table binary sysfs
|
||||
|
||||
AMD MI300A MCM provides GET_METRICS_TABLE message to retrieve
|
||||
most of the system management information from SMU in one go.
|
||||
|
||||
The metrics table is made available as hexadecimal sysfs binary file
|
||||
under per socket sysfs directory created at
|
||||
/sys/devices/platform/amd_hsmp/socket%d/metrics_bin
|
||||
|
||||
Note: lseek() is not supported as entire metrics table is read.
|
||||
|
||||
Metrics table definitions will be documented as part of Public PPR.
|
||||
The same is defined in the amd_hsmp.h header.
|
||||
|
||||
|
||||
An example
|
||||
==========
|
||||
|
||||
|
@ -222,6 +222,7 @@
|
||||
#define MSR_INTEGRITY_CAPS_ARRAY_BIST BIT(MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT)
|
||||
#define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4
|
||||
#define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT)
|
||||
#define MSR_INTEGRITY_CAPS_SAF_GEN_MASK GENMASK_ULL(10, 9)
|
||||
|
||||
#define MSR_LBR_NHM_FROM 0x00000680
|
||||
#define MSR_LBR_NHM_TO 0x000006c0
|
||||
|
@ -47,6 +47,9 @@ enum hsmp_message_ids {
|
||||
HSMP_SET_PCI_RATE, /* 20h Control link rate on PCIe devices */
|
||||
HSMP_SET_POWER_MODE, /* 21h Select power efficiency profile policy */
|
||||
HSMP_SET_PSTATE_MAX_MIN, /* 22h Set the max and min DF P-State */
|
||||
HSMP_GET_METRIC_TABLE_VER, /* 23h Get metrics table version */
|
||||
HSMP_GET_METRIC_TABLE, /* 24h Get metrics table */
|
||||
HSMP_GET_METRIC_TABLE_DRAM_ADDR,/* 25h Get metrics table dram address */
|
||||
HSMP_MSG_ID_MAX,
|
||||
};
|
||||
|
||||
@ -64,6 +67,14 @@ enum hsmp_msg_type {
|
||||
HSMP_GET = 1,
|
||||
};
|
||||
|
||||
enum hsmp_proto_versions {
|
||||
HSMP_PROTO_VER2 = 2,
|
||||
HSMP_PROTO_VER3,
|
||||
HSMP_PROTO_VER4,
|
||||
HSMP_PROTO_VER5,
|
||||
HSMP_PROTO_VER6
|
||||
};
|
||||
|
||||
struct hsmp_msg_desc {
|
||||
int num_args;
|
||||
int response_sz;
|
||||
@ -295,6 +306,104 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] = {
|
||||
* input: args[0] = min df pstate[15:8] + max df pstate[7:0]
|
||||
*/
|
||||
{1, 0, HSMP_SET},
|
||||
|
||||
/*
|
||||
* HSMP_GET_METRIC_TABLE_VER, num_args = 0, response_sz = 1
|
||||
* output: args[0] = metrics table version
|
||||
*/
|
||||
{0, 1, HSMP_GET},
|
||||
|
||||
/*
|
||||
* HSMP_GET_METRIC_TABLE, num_args = 0, response_sz = 0
|
||||
*/
|
||||
{0, 0, HSMP_GET},
|
||||
|
||||
/*
|
||||
* HSMP_GET_METRIC_TABLE_DRAM_ADDR, num_args = 0, response_sz = 2
|
||||
* output: args[0] = lower 32 bits of the address
|
||||
* output: args[1] = upper 32 bits of the address
|
||||
*/
|
||||
{0, 2, HSMP_GET},
|
||||
};
|
||||
|
||||
/* Metrics table (supported only with proto version 6) */
|
||||
struct hsmp_metric_table {
|
||||
__u32 accumulation_counter;
|
||||
|
||||
/* TEMPERATURE */
|
||||
__u32 max_socket_temperature;
|
||||
__u32 max_vr_temperature;
|
||||
__u32 max_hbm_temperature;
|
||||
__u64 max_socket_temperature_acc;
|
||||
__u64 max_vr_temperature_acc;
|
||||
__u64 max_hbm_temperature_acc;
|
||||
|
||||
/* POWER */
|
||||
__u32 socket_power_limit;
|
||||
__u32 max_socket_power_limit;
|
||||
__u32 socket_power;
|
||||
|
||||
/* ENERGY */
|
||||
__u64 timestamp;
|
||||
__u64 socket_energy_acc;
|
||||
__u64 ccd_energy_acc;
|
||||
__u64 xcd_energy_acc;
|
||||
__u64 aid_energy_acc;
|
||||
__u64 hbm_energy_acc;
|
||||
|
||||
/* FREQUENCY */
|
||||
__u32 cclk_frequency_limit;
|
||||
__u32 gfxclk_frequency_limit;
|
||||
__u32 fclk_frequency;
|
||||
__u32 uclk_frequency;
|
||||
__u32 socclk_frequency[4];
|
||||
__u32 vclk_frequency[4];
|
||||
__u32 dclk_frequency[4];
|
||||
__u32 lclk_frequency[4];
|
||||
__u64 gfxclk_frequency_acc[8];
|
||||
__u64 cclk_frequency_acc[96];
|
||||
|
||||
/* FREQUENCY RANGE */
|
||||
__u32 max_cclk_frequency;
|
||||
__u32 min_cclk_frequency;
|
||||
__u32 max_gfxclk_frequency;
|
||||
__u32 min_gfxclk_frequency;
|
||||
__u32 fclk_frequency_table[4];
|
||||
__u32 uclk_frequency_table[4];
|
||||
__u32 socclk_frequency_table[4];
|
||||
__u32 vclk_frequency_table[4];
|
||||
__u32 dclk_frequency_table[4];
|
||||
__u32 lclk_frequency_table[4];
|
||||
__u32 max_lclk_dpm_range;
|
||||
__u32 min_lclk_dpm_range;
|
||||
|
||||
/* XGMI */
|
||||
__u32 xgmi_width;
|
||||
__u32 xgmi_bitrate;
|
||||
__u64 xgmi_read_bandwidth_acc[8];
|
||||
__u64 xgmi_write_bandwidth_acc[8];
|
||||
|
||||
/* ACTIVITY */
|
||||
__u32 socket_c0_residency;
|
||||
__u32 socket_gfx_busy;
|
||||
__u32 dram_bandwidth_utilization;
|
||||
__u64 socket_c0_residency_acc;
|
||||
__u64 socket_gfx_busy_acc;
|
||||
__u64 dram_bandwidth_acc;
|
||||
__u32 max_dram_bandwidth;
|
||||
__u64 dram_bandwidth_utilization_acc;
|
||||
__u64 pcie_bandwidth_acc[4];
|
||||
|
||||
/* THROTTLERS */
|
||||
__u32 prochot_residency_acc;
|
||||
__u32 ppt_residency_acc;
|
||||
__u32 socket_thm_residency_acc;
|
||||
__u32 vr_thm_residency_acc;
|
||||
__u32 hbm_thm_residency_acc;
|
||||
__u32 spare;
|
||||
|
||||
/* New items at the end to maintain driver compatibility */
|
||||
__u32 gfxclk_frequency[8];
|
||||
};
|
||||
|
||||
/* Reset to default packing */
|
||||
|
@ -1028,17 +1028,15 @@ static int mlxbf_bootctl_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mlxbf_bootctl_remove(struct platform_device *pdev)
|
||||
static void mlxbf_bootctl_remove(struct platform_device *pdev)
|
||||
{
|
||||
sysfs_remove_bin_file(&pdev->dev.kobj,
|
||||
&mlxbf_bootctl_bootfifo_sysfs_attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mlxbf_bootctl_driver = {
|
||||
.probe = mlxbf_bootctl_probe,
|
||||
.remove = mlxbf_bootctl_remove,
|
||||
.remove_new = mlxbf_bootctl_remove,
|
||||
.driver = {
|
||||
.name = "mlxbf-bootctl",
|
||||
.dev_groups = mlxbf_bootctl_groups,
|
||||
|
@ -30,14 +30,16 @@
|
||||
|
||||
#define MLXBF_PMC_EVENT_SET_BF1 0
|
||||
#define MLXBF_PMC_EVENT_SET_BF2 1
|
||||
#define MLXBF_PMC_EVENT_SET_BF3 2
|
||||
#define MLXBF_PMC_EVENT_INFO_LEN 100
|
||||
|
||||
#define MLXBF_PMC_MAX_BLOCKS 30
|
||||
#define MLXBF_PMC_MAX_ATTRS 30
|
||||
#define MLXBF_PMC_MAX_ATTRS 70
|
||||
#define MLXBF_PMC_INFO_SZ 4
|
||||
#define MLXBF_PMC_REG_SIZE 8
|
||||
#define MLXBF_PMC_L3C_REG_SIZE 4
|
||||
|
||||
#define MLXBF_PMC_TYPE_CRSPACE 2
|
||||
#define MLXBF_PMC_TYPE_COUNTER 1
|
||||
#define MLXBF_PMC_TYPE_REGISTER 0
|
||||
|
||||
@ -78,6 +80,16 @@
|
||||
#define MLXBF_PMC_L3C_PERF_CNT_LOW_VAL GENMASK(31, 0)
|
||||
#define MLXBF_PMC_L3C_PERF_CNT_HIGH_VAL GENMASK(24, 0)
|
||||
|
||||
#define MLXBF_PMC_CRSPACE_PERFMON_REG0 0x0
|
||||
#define MLXBF_PMC_CRSPACE_PERFSEL_SZ 4
|
||||
#define MLXBF_PMC_CRSPACE_PERFSEL0 GENMASK(23, 16)
|
||||
#define MLXBF_PMC_CRSPACE_PERFSEL1 GENMASK(7, 0)
|
||||
#define MLXBF_PMC_CRSPACE_PERFMON_REG0_SZ 0x2
|
||||
#define MLXBF_PMC_CRSPACE_PERFMON_CTL(n) (n * MLXBF_PMC_CRSPACE_PERFMON_REG0_SZ)
|
||||
#define MLXBF_PMC_CRSPACE_PERFMON_EN BIT(30)
|
||||
#define MLXBF_PMC_CRSPACE_PERFMON_CLR BIT(28)
|
||||
#define MLXBF_PMC_CRSPACE_PERFMON_VAL0(n) (MLXBF_PMC_CRSPACE_PERFMON_CTL(n) + 0xc)
|
||||
|
||||
/**
|
||||
* struct mlxbf_pmc_attribute - Structure to hold attribute and block info
|
||||
* for each sysfs entry
|
||||
@ -124,6 +136,9 @@ struct mlxbf_pmc_block_info {
|
||||
* @pdev: The kernel structure representing the device
|
||||
* @total_blocks: Total number of blocks
|
||||
* @tile_count: Number of tiles in the system
|
||||
* @llt_enable: Info on enabled LLTs
|
||||
* @mss_enable: Info on enabled MSSs
|
||||
* @group_num: Group number assigned to each valid block
|
||||
* @hwmon_dev: Hwmon device for bfperf
|
||||
* @block_name: Block name
|
||||
* @block: Block info
|
||||
@ -136,6 +151,9 @@ struct mlxbf_pmc_context {
|
||||
struct platform_device *pdev;
|
||||
uint32_t total_blocks;
|
||||
uint32_t tile_count;
|
||||
uint8_t llt_enable;
|
||||
uint8_t mss_enable;
|
||||
uint32_t group_num;
|
||||
struct device *hwmon_dev;
|
||||
const char *block_name[MLXBF_PMC_MAX_BLOCKS];
|
||||
struct mlxbf_pmc_block_info block[MLXBF_PMC_MAX_BLOCKS];
|
||||
@ -260,7 +278,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_ecc_events[] = {
|
||||
{ 0x348, "DRAM_ECC_ERROR" },
|
||||
};
|
||||
|
||||
static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = {
|
||||
static const struct mlxbf_pmc_events mlxbf_pmc_mss_events_1[] = {
|
||||
{ 0x0, "DISABLE" },
|
||||
{ 0xc0, "RXREQ_MSS" },
|
||||
{ 0xc1, "RXDAT_MSS" },
|
||||
@ -268,6 +286,164 @@ static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = {
|
||||
{ 0xc3, "TXDAT_MSS" },
|
||||
};
|
||||
|
||||
static const struct mlxbf_pmc_events mlxbf_pmc_mss_events_3[] = {
|
||||
{0, "SKYLIB_CDN_TX_FLITS"},
|
||||
{1, "SKYLIB_DDN_TX_FLITS"},
|
||||
{2, "SKYLIB_NDN_TX_FLITS"},
|
||||
{3, "SKYLIB_SDN_TX_FLITS"},
|
||||
{4, "SKYLIB_UDN_TX_FLITS"},
|
||||
{5, "SKYLIB_CDN_RX_FLITS"},
|
||||
{6, "SKYLIB_DDN_RX_FLITS"},
|
||||
{7, "SKYLIB_NDN_RX_FLITS"},
|
||||
{8, "SKYLIB_SDN_RX_FLITS"},
|
||||
{9, "SKYLIB_UDN_RX_FLITS"},
|
||||
{10, "SKYLIB_CDN_TX_STALL"},
|
||||
{11, "SKYLIB_DDN_TX_STALL"},
|
||||
{12, "SKYLIB_NDN_TX_STALL"},
|
||||
{13, "SKYLIB_SDN_TX_STALL"},
|
||||
{14, "SKYLIB_UDN_TX_STALL"},
|
||||
{15, "SKYLIB_CDN_RX_STALL"},
|
||||
{16, "SKYLIB_DDN_RX_STALL"},
|
||||
{17, "SKYLIB_NDN_RX_STALL"},
|
||||
{18, "SKYLIB_SDN_RX_STALL"},
|
||||
{19, "SKYLIB_UDN_RX_STALL"},
|
||||
{20, "SKYLIB_CHI_REQ0_TX_FLITS"},
|
||||
{21, "SKYLIB_CHI_DATA0_TX_FLITS"},
|
||||
{22, "SKYLIB_CHI_RESP0_TX_FLITS"},
|
||||
{23, "SKYLIB_CHI_SNP0_TX_FLITS"},
|
||||
{24, "SKYLIB_CHI_REQ1_TX_FLITS"},
|
||||
{25, "SKYLIB_CHI_DATA1_TX_FLITS"},
|
||||
{26, "SKYLIB_CHI_RESP1_TX_FLITS"},
|
||||
{27, "SKYLIB_CHI_SNP1_TX_FLITS"},
|
||||
{28, "SKYLIB_CHI_REQ2_TX_FLITS"},
|
||||
{29, "SKYLIB_CHI_DATA2_TX_FLITS"},
|
||||
{30, "SKYLIB_CHI_RESP2_TX_FLITS"},
|
||||
{31, "SKYLIB_CHI_SNP2_TX_FLITS"},
|
||||
{32, "SKYLIB_CHI_REQ3_TX_FLITS"},
|
||||
{33, "SKYLIB_CHI_DATA3_TX_FLITS"},
|
||||
{34, "SKYLIB_CHI_RESP3_TX_FLITS"},
|
||||
{35, "SKYLIB_CHI_SNP3_TX_FLITS"},
|
||||
{36, "SKYLIB_TLP_REQ_TX_FLITS"},
|
||||
{37, "SKYLIB_TLP_RESP_TX_FLITS"},
|
||||
{38, "SKYLIB_TLP_META_TX_FLITS"},
|
||||
{39, "SKYLIB_AXIS_DATA_TX_FLITS"},
|
||||
{40, "SKYLIB_AXIS_CRED_TX_FLITS"},
|
||||
{41, "SKYLIB_APB_TX_FLITS"},
|
||||
{42, "SKYLIB_VW_TX_FLITS"},
|
||||
{43, "SKYLIB_GGA_MSN_W_TX_FLITS"},
|
||||
{44, "SKYLIB_GGA_MSN_N_TX_FLITS"},
|
||||
{45, "SKYLIB_CR_REQ_TX_FLITS"},
|
||||
{46, "SKYLIB_CR_RESP_TX_FLITS"},
|
||||
{47, "SKYLIB_MSN_PRNF_TX_FLITS"},
|
||||
{48, "SKYLIB_DBG_DATA_TX_FLITS"},
|
||||
{49, "SKYLIB_DBG_CRED_TX_FLITS"},
|
||||
{50, "SKYLIB_CHI_REQ0_RX_FLITS"},
|
||||
{51, "SKYLIB_CHI_DATA0_RX_FLITS"},
|
||||
{52, "SKYLIB_CHI_RESP0_RX_FLITS"},
|
||||
{53, "SKYLIB_CHI_SNP0_RX_FLITS"},
|
||||
{54, "SKYLIB_CHI_REQ1_RX_FLITS"},
|
||||
{55, "SKYLIB_CHI_DATA1_RX_FLITS"},
|
||||
{56, "SKYLIB_CHI_RESP1_RX_FLITS"},
|
||||
{57, "SKYLIB_CHI_SNP1_RX_FLITS"},
|
||||
{58, "SKYLIB_CHI_REQ2_RX_FLITS"},
|
||||
{59, "SKYLIB_CHI_DATA2_RX_FLITS"},
|
||||
{60, "SKYLIB_CHI_RESP2_RX_FLITS"},
|
||||
{61, "SKYLIB_CHI_SNP2_RX_FLITS"},
|
||||
{62, "SKYLIB_CHI_REQ3_RX_FLITS"},
|
||||
{63, "SKYLIB_CHI_DATA3_RX_FLITS"},
|
||||
{64, "SKYLIB_CHI_RESP3_RX_FLITS"},
|
||||
{65, "SKYLIB_CHI_SNP3_RX_FLITS"},
|
||||
{66, "SKYLIB_TLP_REQ_RX_FLITS"},
|
||||
{67, "SKYLIB_TLP_RESP_RX_FLITS"},
|
||||
{68, "SKYLIB_TLP_META_RX_FLITS"},
|
||||
{69, "SKYLIB_AXIS_DATA_RX_FLITS"},
|
||||
{70, "SKYLIB_AXIS_CRED_RX_FLITS"},
|
||||
{71, "SKYLIB_APB_RX_FLITS"},
|
||||
{72, "SKYLIB_VW_RX_FLITS"},
|
||||
{73, "SKYLIB_GGA_MSN_W_RX_FLITS"},
|
||||
{74, "SKYLIB_GGA_MSN_N_RX_FLITS"},
|
||||
{75, "SKYLIB_CR_REQ_RX_FLITS"},
|
||||
{76, "SKYLIB_CR_RESP_RX_FLITS"},
|
||||
{77, "SKYLIB_MSN_PRNF_RX_FLITS"},
|
||||
{78, "SKYLIB_DBG_DATA_RX_FLITS"},
|
||||
{79, "SKYLIB_DBG_CRED_RX_FLITS"},
|
||||
{80, "SKYLIB_CHI_REQ0_TX_STALL"},
|
||||
{81, "SKYLIB_CHI_DATA0_TX_STALL"},
|
||||
{82, "SKYLIB_CHI_RESP0_TX_STALL"},
|
||||
{83, "SKYLIB_CHI_SNP0_TX_STALL"},
|
||||
{84, "SKYLIB_CHI_REQ1_TX_STALL"},
|
||||
{85, "SKYLIB_CHI_DATA1_TX_STALL"},
|
||||
{86, "SKYLIB_CHI_RESP1_TX_STALL"},
|
||||
{87, "SKYLIB_CHI_SNP1_TX_STALL"},
|
||||
{88, "SKYLIB_CHI_REQ2_TX_STALL"},
|
||||
{89, "SKYLIB_CHI_DATA2_TX_STALL"},
|
||||
{90, "SKYLIB_CHI_RESP2_TX_STALL"},
|
||||
{91, "SKYLIB_CHI_SNP2_TX_STALL"},
|
||||
{92, "SKYLIB_CHI_REQ3_TX_STALL"},
|
||||
{93, "SKYLIB_CHI_DATA3_TX_STALL"},
|
||||
{94, "SKYLIB_CHI_RESP3_TX_STALL"},
|
||||
{95, "SKYLIB_CHI_SNP3_TX_STALL"},
|
||||
{96, "SKYLIB_TLP_REQ_TX_STALL"},
|
||||
{97, "SKYLIB_TLP_RESP_TX_STALL"},
|
||||
{98, "SKYLIB_TLP_META_TX_STALL"},
|
||||
{99, "SKYLIB_AXIS_DATA_TX_STALL"},
|
||||
{100, "SKYLIB_AXIS_CRED_TX_STALL"},
|
||||
{101, "SKYLIB_APB_TX_STALL"},
|
||||
{102, "SKYLIB_VW_TX_STALL"},
|
||||
{103, "SKYLIB_GGA_MSN_W_TX_STALL"},
|
||||
{104, "SKYLIB_GGA_MSN_N_TX_STALL"},
|
||||
{105, "SKYLIB_CR_REQ_TX_STALL"},
|
||||
{106, "SKYLIB_CR_RESP_TX_STALL"},
|
||||
{107, "SKYLIB_MSN_PRNF_TX_STALL"},
|
||||
{108, "SKYLIB_DBG_DATA_TX_STALL"},
|
||||
{109, "SKYLIB_DBG_CRED_TX_STALL"},
|
||||
{110, "SKYLIB_CHI_REQ0_RX_STALL"},
|
||||
{111, "SKYLIB_CHI_DATA0_RX_STALL"},
|
||||
{112, "SKYLIB_CHI_RESP0_RX_STALL"},
|
||||
{113, "SKYLIB_CHI_SNP0_RX_STALL"},
|
||||
{114, "SKYLIB_CHI_REQ1_RX_STALL"},
|
||||
{115, "SKYLIB_CHI_DATA1_RX_STALL"},
|
||||
{116, "SKYLIB_CHI_RESP1_RX_STALL"},
|
||||
{117, "SKYLIB_CHI_SNP1_RX_STALL"},
|
||||
{118, "SKYLIB_CHI_REQ2_RX_STALL"},
|
||||
{119, "SKYLIB_CHI_DATA2_RX_STALL"},
|
||||
{120, "SKYLIB_CHI_RESP2_RX_STALL"},
|
||||
{121, "SKYLIB_CHI_SNP2_RX_STALL"},
|
||||
{122, "SKYLIB_CHI_REQ3_RX_STALL"},
|
||||
{123, "SKYLIB_CHI_DATA3_RX_STALL"},
|
||||
{124, "SKYLIB_CHI_RESP3_RX_STALL"},
|
||||
{125, "SKYLIB_CHI_SNP3_RX_STALL"},
|
||||
{126, "SKYLIB_TLP_REQ_RX_STALL"},
|
||||
{127, "SKYLIB_TLP_RESP_RX_STALL"},
|
||||
{128, "SKYLIB_TLP_META_RX_STALL"},
|
||||
{129, "SKYLIB_AXIS_DATA_RX_STALL"},
|
||||
{130, "SKYLIB_AXIS_CRED_RX_STALL"},
|
||||
{131, "SKYLIB_APB_RX_STALL"},
|
||||
{132, "SKYLIB_VW_RX_STALL"},
|
||||
{133, "SKYLIB_GGA_MSN_W_RX_STALL"},
|
||||
{134, "SKYLIB_GGA_MSN_N_RX_STALL"},
|
||||
{135, "SKYLIB_CR_REQ_RX_STALL"},
|
||||
{136, "SKYLIB_CR_RESP_RX_STALL"},
|
||||
{137, "SKYLIB_MSN_PRNF_RX_STALL"},
|
||||
{138, "SKYLIB_DBG_DATA_RX_STALL"},
|
||||
{139, "SKYLIB_DBG_CRED_RX_STALL"},
|
||||
{140, "SKYLIB_CDN_LOOPBACK_FLITS"},
|
||||
{141, "SKYLIB_DDN_LOOPBACK_FLITS"},
|
||||
{142, "SKYLIB_NDN_LOOPBACK_FLITS"},
|
||||
{143, "SKYLIB_SDN_LOOPBACK_FLITS"},
|
||||
{144, "SKYLIB_UDN_LOOPBACK_FLITS"},
|
||||
{145, "HISTOGRAM_HISTOGRAM_BIN0"},
|
||||
{146, "HISTOGRAM_HISTOGRAM_BIN1"},
|
||||
{147, "HISTOGRAM_HISTOGRAM_BIN2"},
|
||||
{148, "HISTOGRAM_HISTOGRAM_BIN3"},
|
||||
{149, "HISTOGRAM_HISTOGRAM_BIN4"},
|
||||
{150, "HISTOGRAM_HISTOGRAM_BIN5"},
|
||||
{151, "HISTOGRAM_HISTOGRAM_BIN6"},
|
||||
{152, "HISTOGRAM_HISTOGRAM_BIN7"},
|
||||
{153, "HISTOGRAM_HISTOGRAM_BIN8"},
|
||||
{154, "HISTOGRAM_HISTOGRAM_BIN9"},
|
||||
};
|
||||
|
||||
static const struct mlxbf_pmc_events mlxbf_pmc_hnf_events[] = {
|
||||
{ 0x0, "DISABLE" },
|
||||
{ 0x45, "HNF_REQUESTS" },
|
||||
@ -429,6 +605,260 @@ static const struct mlxbf_pmc_events mlxbf_pmc_l3c_events[] = {
|
||||
{ 0x2b, "ANY_REJECT_BANK1" },
|
||||
};
|
||||
|
||||
static const struct mlxbf_pmc_events mlxbf_pmc_llt_events[] = {
|
||||
{0, "HNF0_CYCLES"},
|
||||
{1, "HNF0_REQS_RECEIVED"},
|
||||
{2, "HNF0_REQS_PROCESSED"},
|
||||
{3, "HNF0_DIR_HIT"},
|
||||
{4, "HNF0_DIR_MISS"},
|
||||
{5, "HNF0_DIR_RD_ALLOC"},
|
||||
{6, "HNF0_DIR_WR_ALLOC"},
|
||||
{7, "HNF0_DIR_VICTIM"},
|
||||
{8, "HNF0_CL_HAZARD"},
|
||||
{9, "HNF0_ALL_HAZARD"},
|
||||
{10, "HNF0_PIPE_STALLS"},
|
||||
{11, "HNF0_MEM_READS"},
|
||||
{12, "HNF0_MEM_WRITES"},
|
||||
{13, "HNF0_MEM_ACCESS"},
|
||||
{14, "HNF0_DCL_READ"},
|
||||
{15, "HNF0_DCL_INVAL"},
|
||||
{16, "HNF0_CHI_RXDAT"},
|
||||
{17, "HNF0_CHI_RXRSP"},
|
||||
{18, "HNF0_CHI_TXDAT"},
|
||||
{19, "HNF0_CHI_TXRSP"},
|
||||
{20, "HNF0_CHI_TXSNP"},
|
||||
{21, "HNF0_DCT_SNP"},
|
||||
{22, "HNF0_SNP_FWD_DATA"},
|
||||
{23, "HNF0_SNP_FWD_RSP"},
|
||||
{24, "HNF0_SNP_RSP"},
|
||||
{25, "HNF0_EXCL_FULL"},
|
||||
{26, "HNF0_EXCL_WRITE_F"},
|
||||
{27, "HNF0_EXCL_WRITE_S"},
|
||||
{28, "HNF0_EXCL_WRITE"},
|
||||
{29, "HNF0_EXCL_READ"},
|
||||
{30, "HNF0_REQ_BUF_EMPTY"},
|
||||
{31, "HNF0_ALL_MAFS_BUSY"},
|
||||
{32, "HNF0_TXDAT_NO_LCRD"},
|
||||
{33, "HNF0_TXSNP_NO_LCRD"},
|
||||
{34, "HNF0_TXRSP_NO_LCRD"},
|
||||
{35, "HNF0_TXREQ_NO_LCRD"},
|
||||
{36, "HNF0_WRITE"},
|
||||
{37, "HNF0_READ"},
|
||||
{38, "HNF0_ACCESS"},
|
||||
{39, "HNF0_MAF_N_BUSY"},
|
||||
{40, "HNF0_MAF_N_REQS"},
|
||||
{41, "HNF0_SEL_OPCODE"},
|
||||
{42, "HNF1_CYCLES"},
|
||||
{43, "HNF1_REQS_RECEIVED"},
|
||||
{44, "HNF1_REQS_PROCESSED"},
|
||||
{45, "HNF1_DIR_HIT"},
|
||||
{46, "HNF1_DIR_MISS"},
|
||||
{47, "HNF1_DIR_RD_ALLOC"},
|
||||
{48, "HNF1_DIR_WR_ALLOC"},
|
||||
{49, "HNF1_DIR_VICTIM"},
|
||||
{50, "HNF1_CL_HAZARD"},
|
||||
{51, "HNF1_ALL_HAZARD"},
|
||||
{52, "HNF1_PIPE_STALLS"},
|
||||
{53, "HNF1_MEM_READS"},
|
||||
{54, "HNF1_MEM_WRITES"},
|
||||
{55, "HNF1_MEM_ACCESS"},
|
||||
{56, "HNF1_DCL_READ"},
|
||||
{57, "HNF1_DCL_INVAL"},
|
||||
{58, "HNF1_CHI_RXDAT"},
|
||||
{59, "HNF1_CHI_RXRSP"},
|
||||
{60, "HNF1_CHI_TXDAT"},
|
||||
{61, "HNF1_CHI_TXRSP"},
|
||||
{62, "HNF1_CHI_TXSNP"},
|
||||
{63, "HNF1_DCT_SNP"},
|
||||
{64, "HNF1_SNP_FWD_DATA"},
|
||||
{65, "HNF1_SNP_FWD_RSP"},
|
||||
{66, "HNF1_SNP_RSP"},
|
||||
{67, "HNF1_EXCL_FULL"},
|
||||
{68, "HNF1_EXCL_WRITE_F"},
|
||||
{69, "HNF1_EXCL_WRITE_S"},
|
||||
{70, "HNF1_EXCL_WRITE"},
|
||||
{71, "HNF1_EXCL_READ"},
|
||||
{72, "HNF1_REQ_BUF_EMPTY"},
|
||||
{73, "HNF1_ALL_MAFS_BUSY"},
|
||||
{74, "HNF1_TXDAT_NO_LCRD"},
|
||||
{75, "HNF1_TXSNP_NO_LCRD"},
|
||||
{76, "HNF1_TXRSP_NO_LCRD"},
|
||||
{77, "HNF1_TXREQ_NO_LCRD"},
|
||||
{78, "HNF1_WRITE"},
|
||||
{79, "HNF1_READ"},
|
||||
{80, "HNF1_ACCESS"},
|
||||
{81, "HNF1_MAF_N_BUSY"},
|
||||
{82, "HNF1_MAF_N_REQS"},
|
||||
{83, "HNF1_SEL_OPCODE"},
|
||||
{84, "GDC_BANK0_RD_REQ"},
|
||||
{85, "GDC_BANK0_WR_REQ"},
|
||||
{86, "GDC_BANK0_ALLOCATE"},
|
||||
{87, "GDC_BANK0_HIT"},
|
||||
{88, "GDC_BANK0_MISS"},
|
||||
{89, "GDC_BANK0_INVALIDATE"},
|
||||
{90, "GDC_BANK0_EVICT"},
|
||||
{91, "GDC_BANK0_RD_RESP"},
|
||||
{92, "GDC_BANK0_WR_ACK"},
|
||||
{93, "GDC_BANK0_SNOOP"},
|
||||
{94, "GDC_BANK0_SNOOP_NORMAL"},
|
||||
{95, "GDC_BANK0_SNOOP_FWD"},
|
||||
{96, "GDC_BANK0_SNOOP_STASH"},
|
||||
{97, "GDC_BANK0_SNOOP_STASH_INDPND_RD"},
|
||||
{98, "GDC_BANK0_FOLLOWER"},
|
||||
{99, "GDC_BANK0_FW"},
|
||||
{100, "GDC_BANK0_HIT_DCL_BOTH"},
|
||||
{101, "GDC_BANK0_HIT_DCL_PARTIAL"},
|
||||
{102, "GDC_BANK0_EVICT_DCL"},
|
||||
{103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA0"},
|
||||
{103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA1"},
|
||||
{105, "GDC_BANK0_ARB_STRB"},
|
||||
{106, "GDC_BANK0_ARB_WAIT"},
|
||||
{107, "GDC_BANK0_GGA_STRB"},
|
||||
{108, "GDC_BANK0_GGA_WAIT"},
|
||||
{109, "GDC_BANK0_FW_STRB"},
|
||||
{110, "GDC_BANK0_FW_WAIT"},
|
||||
{111, "GDC_BANK0_SNP_STRB"},
|
||||
{112, "GDC_BANK0_SNP_WAIT"},
|
||||
{113, "GDC_BANK0_MISS_INARB_STRB"},
|
||||
{114, "GDC_BANK0_MISS_INARB_WAIT"},
|
||||
{115, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD0"},
|
||||
{116, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD1"},
|
||||
{117, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD2"},
|
||||
{118, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD3"},
|
||||
{119, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR0"},
|
||||
{120, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR1"},
|
||||
{121, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR2"},
|
||||
{122, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR3"},
|
||||
{123, "GDC_BANK1_RD_REQ"},
|
||||
{124, "GDC_BANK1_WR_REQ"},
|
||||
{125, "GDC_BANK1_ALLOCATE"},
|
||||
{126, "GDC_BANK1_HIT"},
|
||||
{127, "GDC_BANK1_MISS"},
|
||||
{128, "GDC_BANK1_INVALIDATE"},
|
||||
{129, "GDC_BANK1_EVICT"},
|
||||
{130, "GDC_BANK1_RD_RESP"},
|
||||
{131, "GDC_BANK1_WR_ACK"},
|
||||
{132, "GDC_BANK1_SNOOP"},
|
||||
{133, "GDC_BANK1_SNOOP_NORMAL"},
|
||||
{134, "GDC_BANK1_SNOOP_FWD"},
|
||||
{135, "GDC_BANK1_SNOOP_STASH"},
|
||||
{136, "GDC_BANK1_SNOOP_STASH_INDPND_RD"},
|
||||
{137, "GDC_BANK1_FOLLOWER"},
|
||||
{138, "GDC_BANK1_FW"},
|
||||
{139, "GDC_BANK1_HIT_DCL_BOTH"},
|
||||
{140, "GDC_BANK1_HIT_DCL_PARTIAL"},
|
||||
{141, "GDC_BANK1_EVICT_DCL"},
|
||||
{142, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA0"},
|
||||
{143, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA1"},
|
||||
{144, "GDC_BANK1_ARB_STRB"},
|
||||
{145, "GDC_BANK1_ARB_WAIT"},
|
||||
{146, "GDC_BANK1_GGA_STRB"},
|
||||
{147, "GDC_BANK1_GGA_WAIT"},
|
||||
{148, "GDC_BANK1_FW_STRB"},
|
||||
{149, "GDC_BANK1_FW_WAIT"},
|
||||
{150, "GDC_BANK1_SNP_STRB"},
|
||||
{151, "GDC_BANK1_SNP_WAIT"},
|
||||
{152, "GDC_BANK1_MISS_INARB_STRB"},
|
||||
{153, "GDC_BANK1_MISS_INARB_WAIT"},
|
||||
{154, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD0"},
|
||||
{155, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD1"},
|
||||
{156, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD2"},
|
||||
{157, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD3"},
|
||||
{158, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR0"},
|
||||
{159, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR1"},
|
||||
{160, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR2"},
|
||||
{161, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR3"},
|
||||
{162, "HISTOGRAM_HISTOGRAM_BIN0"},
|
||||
{163, "HISTOGRAM_HISTOGRAM_BIN1"},
|
||||
{164, "HISTOGRAM_HISTOGRAM_BIN2"},
|
||||
{165, "HISTOGRAM_HISTOGRAM_BIN3"},
|
||||
{166, "HISTOGRAM_HISTOGRAM_BIN4"},
|
||||
{167, "HISTOGRAM_HISTOGRAM_BIN5"},
|
||||
{168, "HISTOGRAM_HISTOGRAM_BIN6"},
|
||||
{169, "HISTOGRAM_HISTOGRAM_BIN7"},
|
||||
{170, "HISTOGRAM_HISTOGRAM_BIN8"},
|
||||
{171, "HISTOGRAM_HISTOGRAM_BIN9"},
|
||||
};
|
||||
|
||||
static const struct mlxbf_pmc_events mlxbf_pmc_llt_miss_events[] = {
|
||||
{0, "GDC_MISS_MACHINE_RD_REQ"},
|
||||
{1, "GDC_MISS_MACHINE_WR_REQ"},
|
||||
{2, "GDC_MISS_MACHINE_SNP_REQ"},
|
||||
{3, "GDC_MISS_MACHINE_EVICT_REQ"},
|
||||
{4, "GDC_MISS_MACHINE_FW_REQ"},
|
||||
{5, "GDC_MISS_MACHINE_RD_RESP"},
|
||||
{6, "GDC_MISS_MACHINE_WR_RESP"},
|
||||
{7, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP"},
|
||||
{8, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP_TXDAT"},
|
||||
{9, "GDC_MISS_MACHINE_CHI_TXREQ"},
|
||||
{10, "GDC_MISS_MACHINE_CHI_RXRSP"},
|
||||
{11, "GDC_MISS_MACHINE_CHI_TXDAT"},
|
||||
{12, "GDC_MISS_MACHINE_CHI_RXDAT"},
|
||||
{13, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_0"},
|
||||
{14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1 "},
|
||||
{15, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_2"},
|
||||
{16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3 "},
|
||||
{17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0 "},
|
||||
{18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1 "},
|
||||
{19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2 "},
|
||||
{20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3 "},
|
||||
{21, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_0"},
|
||||
{22, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_1"},
|
||||
{23, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_2"},
|
||||
{24, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_3"},
|
||||
{25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0 "},
|
||||
{26, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_1"},
|
||||
{27, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_2"},
|
||||
{28, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_3"},
|
||||
{29, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_0"},
|
||||
{30, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_1"},
|
||||
{31, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_2"},
|
||||
{32, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_3"},
|
||||
{33, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_4"},
|
||||
{34, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_5"},
|
||||
{35, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_6"},
|
||||
{36, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_0"},
|
||||
{37, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_1"},
|
||||
{38, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_0"},
|
||||
{39, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_1"},
|
||||
{40, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_0"},
|
||||
{41, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_1"},
|
||||
{42, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_0"},
|
||||
{43, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_1"},
|
||||
{44, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_0"},
|
||||
{45, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_1"},
|
||||
{46, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_2"},
|
||||
{47, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_3"},
|
||||
{48, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_0"},
|
||||
{49, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_1"},
|
||||
{50, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_0"},
|
||||
{51, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_1"},
|
||||
{52, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_0"},
|
||||
{53, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_1"},
|
||||
{54, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_0"},
|
||||
{55, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_1"},
|
||||
{56, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_2"},
|
||||
{57, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_3"},
|
||||
{58, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_0"},
|
||||
{59, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_1"},
|
||||
{60, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_2"},
|
||||
{61, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_3"},
|
||||
{62, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_4"},
|
||||
{63, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_5"},
|
||||
{64, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_6"},
|
||||
{65, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_7"},
|
||||
{66, "HISTOGRAM_HISTOGRAM_BIN0"},
|
||||
{67, "HISTOGRAM_HISTOGRAM_BIN1"},
|
||||
{68, "HISTOGRAM_HISTOGRAM_BIN2"},
|
||||
{69, "HISTOGRAM_HISTOGRAM_BIN3"},
|
||||
{70, "HISTOGRAM_HISTOGRAM_BIN4"},
|
||||
{71, "HISTOGRAM_HISTOGRAM_BIN5"},
|
||||
{72, "HISTOGRAM_HISTOGRAM_BIN6"},
|
||||
{73, "HISTOGRAM_HISTOGRAM_BIN7"},
|
||||
{74, "HISTOGRAM_HISTOGRAM_BIN8"},
|
||||
{75, "HISTOGRAM_HISTOGRAM_BIN9"},
|
||||
};
|
||||
|
||||
static struct mlxbf_pmc_context *pmc;
|
||||
|
||||
/* UUID used to probe ATF service. */
|
||||
@ -569,8 +999,21 @@ static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk,
|
||||
break;
|
||||
}
|
||||
} else if (strstr(blk, "mss")) {
|
||||
events = mlxbf_pmc_mss_events;
|
||||
*size = ARRAY_SIZE(mlxbf_pmc_mss_events);
|
||||
switch (pmc->event_set) {
|
||||
case MLXBF_PMC_EVENT_SET_BF1:
|
||||
case MLXBF_PMC_EVENT_SET_BF2:
|
||||
events = mlxbf_pmc_mss_events_1;
|
||||
*size = ARRAY_SIZE(mlxbf_pmc_mss_events_1);
|
||||
break;
|
||||
case MLXBF_PMC_EVENT_SET_BF3:
|
||||
events = mlxbf_pmc_mss_events_3;
|
||||
*size = ARRAY_SIZE(mlxbf_pmc_mss_events_3);
|
||||
break;
|
||||
default:
|
||||
events = NULL;
|
||||
*size = 0;
|
||||
break;
|
||||
}
|
||||
} else if (strstr(blk, "ecc")) {
|
||||
events = mlxbf_pmc_ecc_events;
|
||||
*size = ARRAY_SIZE(mlxbf_pmc_ecc_events);
|
||||
@ -586,6 +1029,12 @@ static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk,
|
||||
} else if (strstr(blk, "smmu")) {
|
||||
events = mlxbf_pmc_smgen_events;
|
||||
*size = ARRAY_SIZE(mlxbf_pmc_smgen_events);
|
||||
} else if (strstr(blk, "llt_miss")) {
|
||||
events = mlxbf_pmc_llt_miss_events;
|
||||
*size = ARRAY_SIZE(mlxbf_pmc_llt_miss_events);
|
||||
} else if (strstr(blk, "llt")) {
|
||||
events = mlxbf_pmc_llt_events;
|
||||
*size = ARRAY_SIZE(mlxbf_pmc_llt_events);
|
||||
} else {
|
||||
events = NULL;
|
||||
*size = 0;
|
||||
@ -712,6 +1161,43 @@ static int mlxbf_pmc_program_l3_counter(int blk_num, uint32_t cnt_num,
|
||||
return mlxbf_pmc_write(pmcaddr, MLXBF_PMC_WRITE_REG_32, *wordaddr);
|
||||
}
|
||||
|
||||
/* Method to handle crspace counter programming */
|
||||
static int mlxbf_pmc_program_crspace_counter(int blk_num, uint32_t cnt_num,
|
||||
uint32_t evt)
|
||||
{
|
||||
uint32_t word;
|
||||
void *addr;
|
||||
int ret;
|
||||
|
||||
addr = pmc->block[blk_num].mmio_base +
|
||||
(rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
|
||||
ret = mlxbf_pmc_readl(addr, &word);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cnt_num % 2) {
|
||||
word &= ~MLXBF_PMC_CRSPACE_PERFSEL1;
|
||||
word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL1, evt);
|
||||
} else {
|
||||
word &= ~MLXBF_PMC_CRSPACE_PERFSEL0;
|
||||
word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL0, evt);
|
||||
}
|
||||
|
||||
return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, word);
|
||||
}
|
||||
|
||||
/* Method to clear crspace counter value */
|
||||
static int mlxbf_pmc_clear_crspace_counter(int blk_num, uint32_t cnt_num)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
addr = pmc->block[blk_num].mmio_base +
|
||||
MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) +
|
||||
(cnt_num * 4);
|
||||
|
||||
return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, 0x0);
|
||||
}
|
||||
|
||||
/* Method to program a counter to monitor an event */
|
||||
static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num,
|
||||
uint32_t evt, bool is_l3)
|
||||
@ -724,6 +1210,10 @@ static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num,
|
||||
if (is_l3)
|
||||
return mlxbf_pmc_program_l3_counter(blk_num, cnt_num, evt);
|
||||
|
||||
if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
|
||||
return mlxbf_pmc_program_crspace_counter(blk_num, cnt_num,
|
||||
evt);
|
||||
|
||||
/* Configure the counter */
|
||||
perfctl = FIELD_PREP(MLXBF_PMC_PERFCTL_EN0, 1);
|
||||
perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_EB0, 0);
|
||||
@ -778,7 +1268,7 @@ static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num,
|
||||
{
|
||||
uint32_t perfcnt_low = 0, perfcnt_high = 0;
|
||||
uint64_t value;
|
||||
int status = 0;
|
||||
int status;
|
||||
|
||||
status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
|
||||
MLXBF_PMC_L3C_PERF_CNT_LOW +
|
||||
@ -804,6 +1294,24 @@ static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Method to handle crspace counter reads */
|
||||
static int mlxbf_pmc_read_crspace_counter(int blk_num, uint32_t cnt_num,
|
||||
uint64_t *result)
|
||||
{
|
||||
uint32_t value;
|
||||
int status = 0;
|
||||
|
||||
status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
|
||||
MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) +
|
||||
(cnt_num * 4), &value);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*result = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Method to read the counter value */
|
||||
static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3,
|
||||
uint64_t *result)
|
||||
@ -818,6 +1326,9 @@ static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3,
|
||||
if (is_l3)
|
||||
return mlxbf_pmc_read_l3_counter(blk_num, cnt_num, result);
|
||||
|
||||
if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
|
||||
return mlxbf_pmc_read_crspace_counter(blk_num, cnt_num, result);
|
||||
|
||||
perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE;
|
||||
perfval_offset = perfcfg_offset +
|
||||
pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE;
|
||||
@ -893,6 +1404,30 @@ static int mlxbf_pmc_read_l3_event(int blk_num, uint32_t cnt_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Method to read crspace block event */
|
||||
static int mlxbf_pmc_read_crspace_event(int blk_num, uint32_t cnt_num,
|
||||
uint64_t *result)
|
||||
{
|
||||
uint32_t word, evt;
|
||||
void *addr;
|
||||
int ret;
|
||||
|
||||
addr = pmc->block[blk_num].mmio_base +
|
||||
(rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
|
||||
ret = mlxbf_pmc_readl(addr, &word);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cnt_num % 2)
|
||||
evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL1, word);
|
||||
else
|
||||
evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL0, word);
|
||||
|
||||
*result = evt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Method to find the event currently being monitored by a counter */
|
||||
static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3,
|
||||
uint64_t *result)
|
||||
@ -906,6 +1441,9 @@ static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3,
|
||||
if (is_l3)
|
||||
return mlxbf_pmc_read_l3_event(blk_num, cnt_num, result);
|
||||
|
||||
if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
|
||||
return mlxbf_pmc_read_crspace_event(blk_num, cnt_num, result);
|
||||
|
||||
perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE;
|
||||
perfval_offset = perfcfg_offset +
|
||||
pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE;
|
||||
@ -982,7 +1520,8 @@ static ssize_t mlxbf_pmc_counter_show(struct device *dev,
|
||||
if (strstr(pmc->block_name[blk_num], "l3cache"))
|
||||
is_l3 = true;
|
||||
|
||||
if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) {
|
||||
if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) ||
|
||||
(pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)) {
|
||||
if (mlxbf_pmc_read_counter(blk_num, cnt_num, is_l3, &value))
|
||||
return -EINVAL;
|
||||
} else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) {
|
||||
@ -1040,6 +1579,10 @@ static ssize_t mlxbf_pmc_counter_store(struct device *dev,
|
||||
err = mlxbf_pmc_write_reg(blk_num, offset, data);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
|
||||
if (sscanf(attr->attr.name, "counter%d", &cnt_num) != 1)
|
||||
return -EINVAL;
|
||||
err = mlxbf_pmc_clear_crspace_counter(blk_num, cnt_num);
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
@ -1137,28 +1680,37 @@ static ssize_t mlxbf_pmc_event_list_show(struct device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Show function for "enable" sysfs files - only for l3cache */
|
||||
/* Show function for "enable" sysfs files - only for l3cache & crspace */
|
||||
static ssize_t mlxbf_pmc_enable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mlxbf_pmc_attribute *attr_enable = container_of(
|
||||
attr, struct mlxbf_pmc_attribute, dev_attr);
|
||||
uint32_t perfcnt_cfg;
|
||||
uint32_t perfcnt_cfg, word;
|
||||
int blk_num, value;
|
||||
|
||||
blk_num = attr_enable->nr;
|
||||
|
||||
if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
|
||||
MLXBF_PMC_L3C_PERF_CNT_CFG,
|
||||
&perfcnt_cfg))
|
||||
return -EINVAL;
|
||||
if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
|
||||
if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
|
||||
MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
|
||||
&word))
|
||||
return -EINVAL;
|
||||
|
||||
value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg);
|
||||
value = FIELD_GET(MLXBF_PMC_CRSPACE_PERFMON_EN, word);
|
||||
} else {
|
||||
if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
|
||||
MLXBF_PMC_L3C_PERF_CNT_CFG,
|
||||
&perfcnt_cfg))
|
||||
return -EINVAL;
|
||||
|
||||
value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg);
|
||||
}
|
||||
|
||||
return sysfs_emit(buf, "%d\n", value);
|
||||
}
|
||||
|
||||
/* Store function for "enable" sysfs files - only for l3cache */
|
||||
/* Store function for "enable" sysfs files - only for l3cache & crspace */
|
||||
static ssize_t mlxbf_pmc_enable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@ -1166,6 +1718,7 @@ static ssize_t mlxbf_pmc_enable_store(struct device *dev,
|
||||
struct mlxbf_pmc_attribute *attr_enable = container_of(
|
||||
attr, struct mlxbf_pmc_attribute, dev_attr);
|
||||
int err, en, blk_num;
|
||||
uint32_t word;
|
||||
|
||||
blk_num = attr_enable->nr;
|
||||
|
||||
@ -1173,19 +1726,35 @@ static ssize_t mlxbf_pmc_enable_store(struct device *dev,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!en) {
|
||||
err = mlxbf_pmc_config_l3_counters(blk_num, false, false);
|
||||
if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
|
||||
err = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
|
||||
MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
|
||||
&word);
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
word &= ~MLXBF_PMC_CRSPACE_PERFMON_EN;
|
||||
word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_EN, en);
|
||||
if (en)
|
||||
word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_CLR, 1);
|
||||
|
||||
mlxbf_pmc_write(pmc->block[blk_num].mmio_base +
|
||||
MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
|
||||
MLXBF_PMC_WRITE_REG_32, word);
|
||||
} else {
|
||||
if (en && en != 1)
|
||||
return -EINVAL;
|
||||
|
||||
err = mlxbf_pmc_config_l3_counters(blk_num, false, !!en);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (en == 1) {
|
||||
err = mlxbf_pmc_config_l3_counters(blk_num, false, true);
|
||||
if (err)
|
||||
return err;
|
||||
err = mlxbf_pmc_config_l3_counters(blk_num, true, false);
|
||||
if (err)
|
||||
return err;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
if (en == 1) {
|
||||
err = mlxbf_pmc_config_l3_counters(blk_num, true, false);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -1206,7 +1775,8 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, int blk_num)
|
||||
attr = NULL;
|
||||
|
||||
/* "enable" sysfs to start/stop the counters. Only in L3C blocks */
|
||||
if (strstr(pmc->block_name[blk_num], "l3cache")) {
|
||||
if (strstr(pmc->block_name[blk_num], "l3cache") ||
|
||||
((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) {
|
||||
attr = &pmc->block[blk_num].attr_enable;
|
||||
attr->dev_attr.attr.mode = 0644;
|
||||
attr->dev_attr.show = mlxbf_pmc_enable_show;
|
||||
@ -1297,7 +1867,8 @@ static int mlxbf_pmc_create_groups(struct device *dev, int blk_num)
|
||||
int err;
|
||||
|
||||
/* Populate attributes based on counter type */
|
||||
if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER)
|
||||
if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) ||
|
||||
(pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))
|
||||
err = mlxbf_pmc_init_perftype_counter(dev, blk_num);
|
||||
else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER)
|
||||
err = mlxbf_pmc_init_perftype_reg(dev, blk_num);
|
||||
@ -1311,7 +1882,8 @@ static int mlxbf_pmc_create_groups(struct device *dev, int blk_num)
|
||||
pmc->block[blk_num].block_attr_grp.attrs = pmc->block[blk_num].block_attr;
|
||||
pmc->block[blk_num].block_attr_grp.name = devm_kasprintf(
|
||||
dev, GFP_KERNEL, pmc->block_name[blk_num]);
|
||||
pmc->groups[blk_num] = &pmc->block[blk_num].block_attr_grp;
|
||||
pmc->groups[pmc->group_num] = &pmc->block[blk_num].block_attr_grp;
|
||||
pmc->group_num++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1334,13 +1906,52 @@ static int mlxbf_pmc_map_counters(struct device *dev)
|
||||
int i, tile_num, ret;
|
||||
|
||||
for (i = 0; i < pmc->total_blocks; ++i) {
|
||||
if (strstr(pmc->block_name[i], "tile")) {
|
||||
/* Create sysfs for tiles only if block number < tile_count */
|
||||
if (strstr(pmc->block_name[i], "tilenet")) {
|
||||
if (sscanf(pmc->block_name[i], "tilenet%d", &tile_num) != 1)
|
||||
continue;
|
||||
|
||||
if (tile_num >= pmc->tile_count)
|
||||
continue;
|
||||
} else if (strstr(pmc->block_name[i], "tile")) {
|
||||
if (sscanf(pmc->block_name[i], "tile%d", &tile_num) != 1)
|
||||
return -EINVAL;
|
||||
continue;
|
||||
|
||||
if (tile_num >= pmc->tile_count)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create sysfs only for enabled MSS blocks */
|
||||
if (strstr(pmc->block_name[i], "mss") &&
|
||||
pmc->event_set == MLXBF_PMC_EVENT_SET_BF3) {
|
||||
int mss_num;
|
||||
|
||||
if (sscanf(pmc->block_name[i], "mss%d", &mss_num) != 1)
|
||||
continue;
|
||||
|
||||
if (!((pmc->mss_enable >> mss_num) & 0x1))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create sysfs only for enabled LLT blocks */
|
||||
if (strstr(pmc->block_name[i], "llt_miss")) {
|
||||
int llt_num;
|
||||
|
||||
if (sscanf(pmc->block_name[i], "llt_miss%d", &llt_num) != 1)
|
||||
continue;
|
||||
|
||||
if (!((pmc->llt_enable >> llt_num) & 0x1))
|
||||
continue;
|
||||
} else if (strstr(pmc->block_name[i], "llt")) {
|
||||
int llt_num;
|
||||
|
||||
if (sscanf(pmc->block_name[i], "llt%d", &llt_num) != 1)
|
||||
continue;
|
||||
|
||||
if (!((pmc->llt_enable >> llt_num) & 0x1))
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = device_property_read_u64_array(dev, pmc->block_name[i],
|
||||
info, MLXBF_PMC_INFO_SZ);
|
||||
if (ret)
|
||||
@ -1417,6 +2028,8 @@ static int mlxbf_pmc_probe(struct platform_device *pdev)
|
||||
pmc->event_set = MLXBF_PMC_EVENT_SET_BF1;
|
||||
else if (!strcmp(hid, "MLNXBFD1"))
|
||||
pmc->event_set = MLXBF_PMC_EVENT_SET_BF2;
|
||||
else if (!strcmp(hid, "MLNXBFD2"))
|
||||
pmc->event_set = MLXBF_PMC_EVENT_SET_BF3;
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
@ -1430,11 +2043,19 @@ static int mlxbf_pmc_probe(struct platform_device *pdev)
|
||||
if (ret != pmc->total_blocks)
|
||||
return -EFAULT;
|
||||
|
||||
ret = device_property_read_u32(dev, "tile_num", &pmc->tile_count);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (device_property_read_u32(dev, "tile_num", &pmc->tile_count)) {
|
||||
if (device_property_read_u8(dev, "llt_enable", &pmc->llt_enable)) {
|
||||
dev_err(dev, "Number of tiles/LLTs undefined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (device_property_read_u8(dev, "mss_enable", &pmc->mss_enable)) {
|
||||
dev_err(dev, "Number of tiles/MSSs undefined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
pmc->pdev = pdev;
|
||||
pmc->group_num = 0;
|
||||
|
||||
ret = mlxbf_pmc_map_counters(dev);
|
||||
if (ret)
|
||||
@ -1449,6 +2070,7 @@ static int mlxbf_pmc_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0", 0 },
|
||||
{ "MLNXBFD1", 0 },
|
||||
{ "MLNXBFD2", 0 },
|
||||
{}, };
|
||||
|
||||
MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids);
|
||||
|
@ -1364,13 +1364,11 @@ fail:
|
||||
}
|
||||
|
||||
/* Device remove function. */
|
||||
static int mlxbf_tmfifo_remove(struct platform_device *pdev)
|
||||
static void mlxbf_tmfifo_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mlxbf_tmfifo *fifo = platform_get_drvdata(pdev);
|
||||
|
||||
mlxbf_tmfifo_cleanup(fifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id mlxbf_tmfifo_acpi_match[] = {
|
||||
@ -1381,7 +1379,7 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match);
|
||||
|
||||
static struct platform_driver mlxbf_tmfifo_driver = {
|
||||
.probe = mlxbf_tmfifo_probe,
|
||||
.remove = mlxbf_tmfifo_remove,
|
||||
.remove_new = mlxbf_tmfifo_remove,
|
||||
.driver = {
|
||||
.name = "bf-tmfifo",
|
||||
.acpi_match_table = mlxbf_tmfifo_acpi_match,
|
||||
|
@ -786,15 +786,13 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxreg_hotplug_remove(struct platform_device *pdev)
|
||||
static void mlxreg_hotplug_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
/* Clean interrupts setup. */
|
||||
mlxreg_hotplug_unset_irq(priv);
|
||||
devm_free_irq(&pdev->dev, priv->irq, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mlxreg_hotplug_driver = {
|
||||
@ -802,7 +800,7 @@ static struct platform_driver mlxreg_hotplug_driver = {
|
||||
.name = "mlxreg-hotplug",
|
||||
},
|
||||
.probe = mlxreg_hotplug_probe,
|
||||
.remove = mlxreg_hotplug_remove,
|
||||
.remove_new = mlxreg_hotplug_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(mlxreg_hotplug_driver);
|
||||
|
@ -263,13 +263,11 @@ static int mlxreg_io_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxreg_io_remove(struct platform_device *pdev)
|
||||
static void mlxreg_io_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mlxreg_io_priv_data *priv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
mutex_destroy(&priv->io_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mlxreg_io_driver = {
|
||||
@ -277,7 +275,7 @@ static struct platform_driver mlxreg_io_driver = {
|
||||
.name = "mlxreg-io",
|
||||
},
|
||||
.probe = mlxreg_io_probe,
|
||||
.remove = mlxreg_io_remove,
|
||||
.remove_new = mlxreg_io_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(mlxreg_io_driver);
|
||||
|
@ -907,7 +907,7 @@ i2c_get_adapter_fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlxreg_lc_remove(struct platform_device *pdev)
|
||||
static void mlxreg_lc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev);
|
||||
struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev);
|
||||
@ -921,7 +921,7 @@ static int mlxreg_lc_remove(struct platform_device *pdev)
|
||||
* is nothing to remove.
|
||||
*/
|
||||
if (!data->notifier || !data->notifier->handle)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/* Clear event notification callback and handle. */
|
||||
data->notifier->user_handler = NULL;
|
||||
@ -940,13 +940,11 @@ static int mlxreg_lc_remove(struct platform_device *pdev)
|
||||
i2c_put_adapter(data->hpdev.adapter);
|
||||
data->hpdev.adapter = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mlxreg_lc_driver = {
|
||||
.probe = mlxreg_lc_probe,
|
||||
.remove = mlxreg_lc_remove,
|
||||
.remove_new = mlxreg_lc_remove,
|
||||
.driver = {
|
||||
.name = "mlxreg-lc",
|
||||
},
|
||||
|
@ -1217,7 +1217,7 @@ static int nvsw_sn2201_probe(struct platform_device *pdev)
|
||||
return nvsw_sn2201_config_pre_init(nvsw_sn2201);
|
||||
}
|
||||
|
||||
static int nvsw_sn2201_remove(struct platform_device *pdev)
|
||||
static void nvsw_sn2201_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct nvsw_sn2201 *nvsw_sn2201 = platform_get_drvdata(pdev);
|
||||
|
||||
@ -1239,8 +1239,6 @@ static int nvsw_sn2201_remove(struct platform_device *pdev)
|
||||
/* Unregister I2C controller. */
|
||||
if (nvsw_sn2201->pdev_i2c)
|
||||
platform_device_unregister(nvsw_sn2201->pdev_i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id nvsw_sn2201_acpi_ids[] = {
|
||||
@ -1252,7 +1250,7 @@ MODULE_DEVICE_TABLE(acpi, nvsw_sn2201_acpi_ids);
|
||||
|
||||
static struct platform_driver nvsw_sn2201_driver = {
|
||||
.probe = nvsw_sn2201_probe,
|
||||
.remove = nvsw_sn2201_remove,
|
||||
.remove_new = nvsw_sn2201_remove,
|
||||
.driver = {
|
||||
.name = "nvsw-sn2201",
|
||||
.acpi_match_table = nvsw_sn2201_acpi_ids,
|
||||
|
@ -226,14 +226,13 @@ static int __init s3_wmi_probe(struct platform_device *pdev)
|
||||
return error;
|
||||
}
|
||||
|
||||
static int s3_wmi_remove(struct platform_device *device)
|
||||
static void s3_wmi_remove(struct platform_device *device)
|
||||
{
|
||||
/* remove the hotplug context from the acpi device */
|
||||
s3_wmi.touchscreen_adev->hp = NULL;
|
||||
|
||||
/* reinstall the actual PNPC0C0D LID default handle */
|
||||
acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused s3_wmi_resume(struct device *dev)
|
||||
@ -248,7 +247,7 @@ static struct platform_driver s3_wmi_driver = {
|
||||
.name = "surface3-wmi",
|
||||
.pm = &s3_wmi_pm,
|
||||
},
|
||||
.remove = s3_wmi_remove,
|
||||
.remove_new = s3_wmi_remove,
|
||||
};
|
||||
|
||||
static int __init s3_wmi_init(void)
|
||||
|
@ -854,7 +854,7 @@ err_enable_events:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int san_remove(struct platform_device *pdev)
|
||||
static void san_remove(struct platform_device *pdev)
|
||||
{
|
||||
acpi_handle san = ACPI_HANDLE(&pdev->dev);
|
||||
|
||||
@ -868,8 +868,6 @@ static int san_remove(struct platform_device *pdev)
|
||||
* all delayed works they may have spawned are run to completion.
|
||||
*/
|
||||
flush_workqueue(san_wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id san_match[] = {
|
||||
@ -880,7 +878,7 @@ MODULE_DEVICE_TABLE(acpi, san_match);
|
||||
|
||||
static struct platform_driver surface_acpi_notify = {
|
||||
.probe = san_probe,
|
||||
.remove = san_remove,
|
||||
.remove_new = san_remove,
|
||||
.driver = {
|
||||
.name = "surface_acpi_notify",
|
||||
.acpi_match_table = san_match,
|
||||
|
@ -714,7 +714,7 @@ static int ssam_dbg_device_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssam_dbg_device_remove(struct platform_device *pdev)
|
||||
static void ssam_dbg_device_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ssam_cdev *cdev = platform_get_drvdata(pdev);
|
||||
struct ssam_cdev_client *client;
|
||||
@ -757,14 +757,13 @@ static int ssam_dbg_device_remove(struct platform_device *pdev)
|
||||
misc_deregister(&cdev->mdev);
|
||||
|
||||
ssam_cdev_put(cdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device *ssam_cdev_device;
|
||||
|
||||
static struct platform_driver ssam_cdev_driver = {
|
||||
.probe = ssam_dbg_device_probe,
|
||||
.remove = ssam_dbg_device_remove,
|
||||
.remove_new = ssam_dbg_device_remove,
|
||||
.driver = {
|
||||
.name = SSAM_CDEV_DEVICE_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -418,19 +418,18 @@ static int ssam_platform_hub_probe(struct platform_device *pdev)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ssam_platform_hub_remove(struct platform_device *pdev)
|
||||
static void ssam_platform_hub_remove(struct platform_device *pdev)
|
||||
{
|
||||
const struct software_node **nodes = platform_get_drvdata(pdev);
|
||||
|
||||
ssam_remove_clients(&pdev->dev);
|
||||
set_secondary_fwnode(&pdev->dev, NULL);
|
||||
software_node_unregister_node_group(nodes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ssam_platform_hub_driver = {
|
||||
.probe = ssam_platform_hub_probe,
|
||||
.remove = ssam_platform_hub_remove,
|
||||
.remove_new = ssam_platform_hub_remove,
|
||||
.driver = {
|
||||
.name = "surface_aggregator_platform_hub",
|
||||
.acpi_match_table = ssam_platform_hub_match,
|
||||
|
@ -1168,10 +1168,9 @@ static int surface_dtx_platform_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int surface_dtx_platform_remove(struct platform_device *pdev)
|
||||
static void surface_dtx_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
sdtx_device_destroy(platform_get_drvdata(pdev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id surface_dtx_acpi_match[] = {
|
||||
@ -1182,7 +1181,7 @@ MODULE_DEVICE_TABLE(acpi, surface_dtx_acpi_match);
|
||||
|
||||
static struct platform_driver surface_dtx_platform_driver = {
|
||||
.probe = surface_dtx_platform_probe,
|
||||
.remove = surface_dtx_platform_remove,
|
||||
.remove_new = surface_dtx_platform_remove,
|
||||
.driver = {
|
||||
.name = "surface_dtx_pltf",
|
||||
.acpi_match_table = surface_dtx_acpi_match,
|
||||
|
@ -267,20 +267,18 @@ static int surface_gpe_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int surface_gpe_remove(struct platform_device *pdev)
|
||||
static void surface_gpe_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct surface_lid_device *lid = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
/* restore default behavior without this module */
|
||||
surface_lid_enable_wakeup(&pdev->dev, false);
|
||||
acpi_disable_gpe(NULL, lid->gpe_number);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver surface_gpe_driver = {
|
||||
.probe = surface_gpe_probe,
|
||||
.remove = surface_gpe_remove,
|
||||
.remove_new = surface_gpe_remove,
|
||||
.driver = {
|
||||
.name = "surface_gpe",
|
||||
.pm = &surface_gpe_pm,
|
||||
|
@ -183,7 +183,7 @@ static int shps_setup_irq(struct platform_device *pdev, enum shps_irq_type type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int surface_hotplug_remove(struct platform_device *pdev)
|
||||
static void surface_hotplug_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct shps_device *sdev = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
@ -195,8 +195,6 @@ static int surface_hotplug_remove(struct platform_device *pdev)
|
||||
|
||||
mutex_destroy(&sdev->lock[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int surface_hotplug_probe(struct platform_device *pdev)
|
||||
@ -261,7 +259,7 @@ MODULE_DEVICE_TABLE(acpi, surface_hotplug_acpi_match);
|
||||
|
||||
static struct platform_driver surface_hotplug_driver = {
|
||||
.probe = surface_hotplug_probe,
|
||||
.remove = surface_hotplug_remove,
|
||||
.remove_new = surface_hotplug_remove,
|
||||
.driver = {
|
||||
.name = "surface_hotplug",
|
||||
.acpi_match_table = surface_hotplug_acpi_match,
|
||||
|
@ -988,6 +988,17 @@ config TOUCHSCREEN_DMI
|
||||
the OS-image for the device. This option supplies the missing info.
|
||||
Enable this for x86 tablets with Silead or Chipone touchscreens.
|
||||
|
||||
config INSPUR_PLATFORM_PROFILE
|
||||
tristate "Inspur WMI platform profile driver"
|
||||
depends on ACPI_WMI
|
||||
select ACPI_PLATFORM_PROFILE
|
||||
help
|
||||
This will allow users to determine and control the platform modes
|
||||
between low-power, balanced and performance modes.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called inspur-platform-profile.
|
||||
|
||||
source "drivers/platform/x86/x86-android-tablets/Kconfig"
|
||||
|
||||
config FW_ATTR_CLASS
|
||||
|
@ -98,6 +98,9 @@ obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o
|
||||
# before toshiba_acpi initializes
|
||||
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
|
||||
|
||||
# Inspur
|
||||
obj-$(CONFIG_INSPUR_PLATFORM_PROFILE) += inspur_platform_profile.o
|
||||
|
||||
# Laptop drivers
|
||||
obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
|
||||
obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
|
||||
|
@ -1922,7 +1922,6 @@ static void acer_rfkill_exit(void)
|
||||
rfkill_unregister(threeg_rfkill);
|
||||
rfkill_destroy(threeg_rfkill);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void acer_wmi_notify(u32 value, void *context)
|
||||
@ -2517,7 +2516,6 @@ static void __exit acer_wmi_exit(void)
|
||||
platform_driver_unregister(&acer_platform_driver);
|
||||
|
||||
pr_info("Acer Laptop WMI Extras unloaded\n");
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(acer_wmi_init);
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
#define DRIVER_NAME "amd_hsmp"
|
||||
#define DRIVER_VERSION "1.0"
|
||||
#define DRIVER_VERSION "2.0"
|
||||
|
||||
/* HSMP Status / Error codes */
|
||||
#define HSMP_STATUS_NOT_READY 0x00
|
||||
@ -47,9 +47,29 @@
|
||||
#define HSMP_INDEX_REG 0xc4
|
||||
#define HSMP_DATA_REG 0xc8
|
||||
|
||||
static struct semaphore *hsmp_sem;
|
||||
#define HSMP_CDEV_NAME "hsmp_cdev"
|
||||
#define HSMP_DEVNODE_NAME "hsmp"
|
||||
#define HSMP_METRICS_TABLE_NAME "metrics_bin"
|
||||
|
||||
static struct miscdevice hsmp_device;
|
||||
#define HSMP_ATTR_GRP_NAME_SIZE 10
|
||||
|
||||
struct hsmp_socket {
|
||||
struct bin_attribute hsmp_attr;
|
||||
void __iomem *metric_tbl_addr;
|
||||
struct semaphore hsmp_sem;
|
||||
char name[HSMP_ATTR_GRP_NAME_SIZE];
|
||||
u16 sock_ind;
|
||||
};
|
||||
|
||||
struct hsmp_plat_device {
|
||||
struct miscdevice hsmp_device;
|
||||
struct hsmp_socket *sock;
|
||||
struct device *dev;
|
||||
u32 proto_ver;
|
||||
u16 num_sockets;
|
||||
};
|
||||
|
||||
static struct hsmp_plat_device plat_dev;
|
||||
|
||||
static int amd_hsmp_rdwr(struct pci_dev *root, u32 address,
|
||||
u32 *value, bool write)
|
||||
@ -188,6 +208,7 @@ static int validate_message(struct hsmp_message *msg)
|
||||
|
||||
int hsmp_send_message(struct hsmp_message *msg)
|
||||
{
|
||||
struct hsmp_socket *sock = &plat_dev.sock[msg->sock_ind];
|
||||
struct amd_northbridge *nb;
|
||||
int ret;
|
||||
|
||||
@ -208,14 +229,13 @@ int hsmp_send_message(struct hsmp_message *msg)
|
||||
* In SMP system timeout of 100 millisecs should
|
||||
* be enough for the previous thread to finish the operation
|
||||
*/
|
||||
ret = down_timeout(&hsmp_sem[msg->sock_ind],
|
||||
msecs_to_jiffies(HSMP_MSG_TIMEOUT));
|
||||
ret = down_timeout(&sock->hsmp_sem, msecs_to_jiffies(HSMP_MSG_TIMEOUT));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = __hsmp_send_message(nb->root, msg);
|
||||
|
||||
up(&hsmp_sem[msg->sock_ind]);
|
||||
up(&sock->hsmp_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -317,32 +337,198 @@ static const struct file_operations hsmp_fops = {
|
||||
.compat_ioctl = hsmp_ioctl,
|
||||
};
|
||||
|
||||
static int hsmp_pltdrv_probe(struct platform_device *pdev)
|
||||
static ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
int i;
|
||||
struct hsmp_socket *sock = bin_attr->private;
|
||||
struct hsmp_message msg = { 0 };
|
||||
int ret;
|
||||
|
||||
hsmp_sem = devm_kzalloc(&pdev->dev,
|
||||
(amd_nb_num() * sizeof(struct semaphore)),
|
||||
GFP_KERNEL);
|
||||
if (!hsmp_sem)
|
||||
/* Do not support lseek(), reads entire metric table */
|
||||
if (count < bin_attr->size) {
|
||||
dev_err(plat_dev.dev, "Wrong buffer size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!sock) {
|
||||
dev_err(plat_dev.dev, "Failed to read attribute private data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg.msg_id = HSMP_GET_METRIC_TABLE;
|
||||
msg.sock_ind = sock->sock_ind;
|
||||
|
||||
ret = hsmp_send_message(&msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
memcpy_fromio(buf, sock->metric_tbl_addr, bin_attr->size);
|
||||
|
||||
return bin_attr->size;
|
||||
}
|
||||
|
||||
static int hsmp_get_tbl_dram_base(u16 sock_ind)
|
||||
{
|
||||
struct hsmp_socket *sock = &plat_dev.sock[sock_ind];
|
||||
struct hsmp_message msg = { 0 };
|
||||
phys_addr_t dram_addr;
|
||||
int ret;
|
||||
|
||||
msg.sock_ind = sock_ind;
|
||||
msg.response_sz = hsmp_msg_desc_table[HSMP_GET_METRIC_TABLE_DRAM_ADDR].response_sz;
|
||||
msg.msg_id = HSMP_GET_METRIC_TABLE_DRAM_ADDR;
|
||||
|
||||
ret = hsmp_send_message(&msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* calculate the metric table DRAM address from lower and upper 32 bits
|
||||
* sent from SMU and ioremap it to virtual address.
|
||||
*/
|
||||
dram_addr = msg.args[0] | ((u64)(msg.args[1]) << 32);
|
||||
if (!dram_addr) {
|
||||
dev_err(plat_dev.dev, "Invalid DRAM address for metric table\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sock->metric_tbl_addr = devm_ioremap(plat_dev.dev, dram_addr,
|
||||
sizeof(struct hsmp_metric_table));
|
||||
if (!sock->metric_tbl_addr) {
|
||||
dev_err(plat_dev.dev, "Failed to ioremap metric table addr\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
|
||||
struct bin_attribute *battr, int id)
|
||||
{
|
||||
if (plat_dev.proto_ver == HSMP_PROTO_VER6)
|
||||
return battr->attr.mode;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hsmp_init_metric_tbl_bin_attr(struct bin_attribute **hattrs, u16 sock_ind)
|
||||
{
|
||||
struct bin_attribute *hattr = &plat_dev.sock[sock_ind].hsmp_attr;
|
||||
|
||||
sysfs_bin_attr_init(hattr);
|
||||
hattr->attr.name = HSMP_METRICS_TABLE_NAME;
|
||||
hattr->attr.mode = 0444;
|
||||
hattr->read = hsmp_metric_tbl_read;
|
||||
hattr->size = sizeof(struct hsmp_metric_table);
|
||||
hattr->private = &plat_dev.sock[sock_ind];
|
||||
hattrs[0] = hattr;
|
||||
|
||||
if (plat_dev.proto_ver == HSMP_PROTO_VER6)
|
||||
return (hsmp_get_tbl_dram_base(sock_ind));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* One bin sysfs for metrics table*/
|
||||
#define NUM_HSMP_ATTRS 1
|
||||
|
||||
static int hsmp_create_sysfs_interface(void)
|
||||
{
|
||||
const struct attribute_group **hsmp_attr_grps;
|
||||
struct bin_attribute **hsmp_bin_attrs;
|
||||
struct attribute_group *attr_grp;
|
||||
int ret;
|
||||
u16 i;
|
||||
|
||||
/* String formatting is currently limited to u8 sockets */
|
||||
if (WARN_ON(plat_dev.num_sockets > U8_MAX))
|
||||
return -ERANGE;
|
||||
|
||||
hsmp_attr_grps = devm_kzalloc(plat_dev.dev, sizeof(struct attribute_group *) *
|
||||
(plat_dev.num_sockets + 1), GFP_KERNEL);
|
||||
if (!hsmp_attr_grps)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < amd_nb_num(); i++)
|
||||
sema_init(&hsmp_sem[i], 1);
|
||||
/* Create a sysfs directory for each socket */
|
||||
for (i = 0; i < plat_dev.num_sockets; i++) {
|
||||
attr_grp = devm_kzalloc(plat_dev.dev, sizeof(struct attribute_group), GFP_KERNEL);
|
||||
if (!attr_grp)
|
||||
return -ENOMEM;
|
||||
|
||||
hsmp_device.name = "hsmp_cdev";
|
||||
hsmp_device.minor = MISC_DYNAMIC_MINOR;
|
||||
hsmp_device.fops = &hsmp_fops;
|
||||
hsmp_device.parent = &pdev->dev;
|
||||
hsmp_device.nodename = "hsmp";
|
||||
hsmp_device.mode = 0644;
|
||||
snprintf(plat_dev.sock[i].name, HSMP_ATTR_GRP_NAME_SIZE, "socket%u", (u8)i);
|
||||
attr_grp->name = plat_dev.sock[i].name;
|
||||
|
||||
return misc_register(&hsmp_device);
|
||||
/* Null terminated list of attributes */
|
||||
hsmp_bin_attrs = devm_kzalloc(plat_dev.dev, sizeof(struct bin_attribute *) *
|
||||
(NUM_HSMP_ATTRS + 1), GFP_KERNEL);
|
||||
if (!hsmp_bin_attrs)
|
||||
return -ENOMEM;
|
||||
|
||||
attr_grp->bin_attrs = hsmp_bin_attrs;
|
||||
attr_grp->is_bin_visible = hsmp_is_sock_attr_visible;
|
||||
hsmp_attr_grps[i] = attr_grp;
|
||||
|
||||
/* Now create the leaf nodes */
|
||||
ret = hsmp_init_metric_tbl_bin_attr(hsmp_bin_attrs, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return devm_device_add_groups(plat_dev.dev, hsmp_attr_grps);
|
||||
}
|
||||
|
||||
static int hsmp_cache_proto_ver(void)
|
||||
{
|
||||
struct hsmp_message msg = { 0 };
|
||||
int ret;
|
||||
|
||||
msg.msg_id = HSMP_GET_PROTO_VER;
|
||||
msg.sock_ind = 0;
|
||||
msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz;
|
||||
|
||||
ret = hsmp_send_message(&msg);
|
||||
if (!ret)
|
||||
plat_dev.proto_ver = msg.args[0];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hsmp_pltdrv_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
plat_dev.sock = devm_kzalloc(&pdev->dev,
|
||||
(plat_dev.num_sockets * sizeof(struct hsmp_socket)),
|
||||
GFP_KERNEL);
|
||||
if (!plat_dev.sock)
|
||||
return -ENOMEM;
|
||||
plat_dev.dev = &pdev->dev;
|
||||
|
||||
for (i = 0; i < plat_dev.num_sockets; i++) {
|
||||
sema_init(&plat_dev.sock[i].hsmp_sem, 1);
|
||||
plat_dev.sock[i].sock_ind = i;
|
||||
}
|
||||
|
||||
plat_dev.hsmp_device.name = HSMP_CDEV_NAME;
|
||||
plat_dev.hsmp_device.minor = MISC_DYNAMIC_MINOR;
|
||||
plat_dev.hsmp_device.fops = &hsmp_fops;
|
||||
plat_dev.hsmp_device.parent = &pdev->dev;
|
||||
plat_dev.hsmp_device.nodename = HSMP_DEVNODE_NAME;
|
||||
plat_dev.hsmp_device.mode = 0644;
|
||||
|
||||
ret = hsmp_cache_proto_ver();
|
||||
if (ret) {
|
||||
dev_err(plat_dev.dev, "Failed to read HSMP protocol version\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hsmp_create_sysfs_interface();
|
||||
if (ret)
|
||||
dev_err(plat_dev.dev, "Failed to create HSMP sysfs interface\n");
|
||||
|
||||
return misc_register(&plat_dev.hsmp_device);
|
||||
}
|
||||
|
||||
static void hsmp_pltdrv_remove(struct platform_device *pdev)
|
||||
{
|
||||
misc_deregister(&hsmp_device);
|
||||
misc_deregister(&plat_dev.hsmp_device);
|
||||
}
|
||||
|
||||
static struct platform_driver amd_hsmp_driver = {
|
||||
@ -358,7 +544,6 @@ static struct platform_device *amd_hsmp_platdev;
|
||||
static int __init hsmp_plt_init(void)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
u16 num_sockets;
|
||||
int i;
|
||||
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD || boot_cpu_data.x86 < 0x19) {
|
||||
@ -371,18 +556,18 @@ static int __init hsmp_plt_init(void)
|
||||
* amd_nb_num() returns number of SMN/DF interfaces present in the system
|
||||
* if we have N SMN/DF interfaces that ideally means N sockets
|
||||
*/
|
||||
num_sockets = amd_nb_num();
|
||||
if (num_sockets == 0)
|
||||
plat_dev.num_sockets = amd_nb_num();
|
||||
if (plat_dev.num_sockets == 0)
|
||||
return ret;
|
||||
|
||||
/* Test the hsmp interface on each socket */
|
||||
for (i = 0; i < num_sockets; i++) {
|
||||
for (i = 0; i < plat_dev.num_sockets; i++) {
|
||||
ret = hsmp_test(i, 0xDEADBEEF);
|
||||
if (ret) {
|
||||
pr_err("HSMP is not supported on Fam:%x model:%x\n",
|
||||
pr_err("HSMP test message failed on Fam:%x model:%x\n",
|
||||
boot_cpu_data.x86, boot_cpu_data.x86_model);
|
||||
pr_err("Or Is HSMP disabled in BIOS ?\n");
|
||||
return -EOPNOTSUPP;
|
||||
pr_err("Is HSMP disabled in BIOS ?\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,9 +52,13 @@
|
||||
#define AMD_S2D_REGISTER_ARGUMENT 0xA88
|
||||
|
||||
/* STB Spill to DRAM Parameters */
|
||||
#define S2D_TELEMETRY_BYTES_MAX 0x100000
|
||||
#define S2D_TELEMETRY_BYTES_MAX 0x100000U
|
||||
#define S2D_RSVD_RAM_SPACE 0x100000
|
||||
#define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000
|
||||
|
||||
/* STB Spill to DRAM Message Definition */
|
||||
#define STB_FORCE_FLUSH_DATA 0xCF
|
||||
|
||||
/* Base address of SMU for mapping physical address to virtual address */
|
||||
#define AMD_PMC_MAPPING_SIZE 0x01000
|
||||
#define AMD_PMC_BASE_ADDR_OFFSET 0x10000
|
||||
@ -119,6 +123,11 @@ enum s2d_arg {
|
||||
S2D_DRAM_SIZE,
|
||||
};
|
||||
|
||||
struct amd_pmc_stb_v2_data {
|
||||
size_t size;
|
||||
u8 data[] __counted_by(size);
|
||||
};
|
||||
|
||||
struct amd_pmc_bit_map {
|
||||
const char *name;
|
||||
u32 bit_mask;
|
||||
@ -157,6 +166,10 @@ static bool disable_workarounds;
|
||||
module_param(disable_workarounds, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs");
|
||||
|
||||
static bool dump_custom_stb;
|
||||
module_param(dump_custom_stb, bool, 0644);
|
||||
MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer");
|
||||
|
||||
static struct amd_pmc_dev pmc;
|
||||
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret);
|
||||
static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf);
|
||||
@ -233,10 +246,30 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = {
|
||||
.release = amd_pmc_stb_debugfs_release,
|
||||
};
|
||||
|
||||
/* Enhanced STB Firmware Reporting Mechanism */
|
||||
static int amd_pmc_stb_handle_efr(struct file *filp)
|
||||
{
|
||||
struct amd_pmc_dev *dev = filp->f_inode->i_private;
|
||||
struct amd_pmc_stb_v2_data *stb_data_arr;
|
||||
u32 fsize;
|
||||
|
||||
fsize = dev->dram_size - S2D_RSVD_RAM_SPACE;
|
||||
stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL);
|
||||
if (!stb_data_arr)
|
||||
return -ENOMEM;
|
||||
|
||||
stb_data_arr->size = fsize;
|
||||
memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize);
|
||||
filp->private_data = stb_data_arr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct amd_pmc_dev *dev = filp->f_inode->i_private;
|
||||
u32 *buf, fsize, num_samples, stb_rdptr_offset = 0;
|
||||
u32 fsize, num_samples, val, stb_rdptr_offset = 0;
|
||||
struct amd_pmc_stb_v2_data *stb_data_arr;
|
||||
int ret;
|
||||
|
||||
/* Write dummy postcode while reading the STB buffer */
|
||||
@ -244,34 +277,55 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
|
||||
if (ret)
|
||||
dev_err(dev->dev, "error writing to STB: %d\n", ret);
|
||||
|
||||
buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Spill to DRAM num_samples uses separate SMU message port */
|
||||
dev->msg_port = 1;
|
||||
|
||||
ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1);
|
||||
if (ret)
|
||||
dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret);
|
||||
|
||||
/*
|
||||
* We have a custom stb size and the PMFW is supposed to give
|
||||
* the enhanced dram size. Note that we land here only for the
|
||||
* platforms that support enhanced dram size reporting.
|
||||
*/
|
||||
if (dump_custom_stb)
|
||||
return amd_pmc_stb_handle_efr(filp);
|
||||
|
||||
/* Get the num_samples to calculate the last push location */
|
||||
ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->s2d_msg_id, true);
|
||||
/* Clear msg_port for other SMU operation */
|
||||
dev->msg_port = 0;
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Start capturing data from the last push location */
|
||||
fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX);
|
||||
stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL);
|
||||
if (!stb_data_arr)
|
||||
return -ENOMEM;
|
||||
|
||||
stb_data_arr->size = fsize;
|
||||
|
||||
/*
|
||||
* Start capturing data from the last push location.
|
||||
* This is for general cases, where the stb limits
|
||||
* are meant for standard usage.
|
||||
*/
|
||||
if (num_samples > S2D_TELEMETRY_BYTES_MAX) {
|
||||
fsize = S2D_TELEMETRY_BYTES_MAX;
|
||||
stb_rdptr_offset = num_samples - fsize;
|
||||
/* First read oldest data starting 1 behind last write till end of ringbuffer */
|
||||
stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX;
|
||||
fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset;
|
||||
|
||||
memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize);
|
||||
/* Second copy the newer samples from offset 0 - last write */
|
||||
memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset);
|
||||
} else {
|
||||
fsize = num_samples;
|
||||
stb_rdptr_offset = 0;
|
||||
memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize);
|
||||
}
|
||||
|
||||
memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize);
|
||||
filp->private_data = buf;
|
||||
filp->private_data = stb_data_arr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -279,11 +333,9 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
|
||||
static ssize_t amd_pmc_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size,
|
||||
loff_t *pos)
|
||||
{
|
||||
if (!filp->private_data)
|
||||
return -EINVAL;
|
||||
struct amd_pmc_stb_v2_data *data = filp->private_data;
|
||||
|
||||
return simple_read_from_buffer(buf, size, pos, filp->private_data,
|
||||
S2D_TELEMETRY_BYTES_MAX);
|
||||
return simple_read_from_buffer(buf, size, pos, data->data, data->size);
|
||||
}
|
||||
|
||||
static int amd_pmc_stb_debugfs_release_v2(struct inode *inode, struct file *filp)
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/i8042.h>
|
||||
|
||||
#include <acpi/video.h>
|
||||
|
||||
#include "asus-wmi.h"
|
||||
|
||||
#define ASUS_NB_WMI_FILE "asus-nb-wmi"
|
||||
@ -606,6 +608,19 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
|
||||
{ KE_END, 0},
|
||||
};
|
||||
|
||||
static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
|
||||
unsigned int *value, bool *autorelease)
|
||||
{
|
||||
switch (*code) {
|
||||
case ASUS_WMI_BRN_DOWN:
|
||||
case ASUS_WMI_BRN_UP:
|
||||
if (acpi_video_handles_brightness_key_presses())
|
||||
*code = ASUS_WMI_KEY_IGNORE;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct asus_wmi_driver asus_nb_wmi_driver = {
|
||||
.name = ASUS_NB_WMI_FILE,
|
||||
.owner = THIS_MODULE,
|
||||
@ -614,6 +629,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
|
||||
.input_name = "Asus WMI hotkeys",
|
||||
.input_phys = ASUS_NB_WMI_FILE "/input0",
|
||||
.detect_quirks = asus_nb_wmi_quirks,
|
||||
.key_filter = asus_nb_wmi_key_filter,
|
||||
};
|
||||
|
||||
|
||||
|
@ -148,16 +148,12 @@ static int asus_wireless_add(struct acpi_device *adev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (id = device_ids; id->id[0]; id++) {
|
||||
if (!strcmp((char *) id->id, acpi_device_hid(adev))) {
|
||||
data->hswc_params =
|
||||
(const struct hswc_params *)id->driver_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!data->hswc_params)
|
||||
id = acpi_match_acpi_device(device_ids, adev);
|
||||
if (!id)
|
||||
return 0;
|
||||
|
||||
data->hswc_params = (const struct hswc_params *)id->driver_data;
|
||||
|
||||
data->wq = create_singlethread_workqueue("asus_wireless_workqueue");
|
||||
if (!data->wq)
|
||||
return -ENOMEM;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_hotplug.h>
|
||||
@ -127,6 +128,10 @@ module_param(fnlock_default, bool, 0444);
|
||||
#define NVIDIA_TEMP_MIN 75
|
||||
#define NVIDIA_TEMP_MAX 87
|
||||
|
||||
#define ASUS_SCREENPAD_BRIGHT_MIN 20
|
||||
#define ASUS_SCREENPAD_BRIGHT_MAX 255
|
||||
#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
|
||||
|
||||
static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
|
||||
|
||||
static int throttle_thermal_policy_write(struct asus_wmi *);
|
||||
@ -212,6 +217,7 @@ struct asus_wmi {
|
||||
|
||||
struct input_dev *inputdev;
|
||||
struct backlight_device *backlight_device;
|
||||
struct backlight_device *screenpad_backlight_device;
|
||||
struct platform_device *platform_device;
|
||||
|
||||
struct led_classdev wlan_led;
|
||||
@ -3776,6 +3782,124 @@ static int is_display_toggle(int code)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Screenpad backlight *******************************************************/
|
||||
|
||||
static int read_screenpad_backlight_power(struct asus_wmi *asus)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* 1 == powered */
|
||||
return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
|
||||
}
|
||||
|
||||
static int read_screenpad_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct asus_wmi *asus = bl_get_data(bd);
|
||||
u32 retval;
|
||||
int err;
|
||||
|
||||
err = read_screenpad_backlight_power(asus);
|
||||
if (err < 0)
|
||||
return err;
|
||||
/* The device brightness can only be read if powered, so return stored */
|
||||
if (err == FB_BLANK_POWERDOWN)
|
||||
return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
|
||||
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
}
|
||||
|
||||
static int update_screenpad_bl_status(struct backlight_device *bd)
|
||||
{
|
||||
struct asus_wmi *asus = bl_get_data(bd);
|
||||
int power, err = 0;
|
||||
u32 ctrl_param;
|
||||
|
||||
power = read_screenpad_backlight_power(asus);
|
||||
if (power < 0)
|
||||
return power;
|
||||
|
||||
if (bd->props.power != power) {
|
||||
if (power != FB_BLANK_UNBLANK) {
|
||||
/* Only brightness > 0 can power it back on */
|
||||
ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT,
|
||||
ctrl_param, NULL);
|
||||
} else {
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL);
|
||||
}
|
||||
} else if (power == FB_BLANK_UNBLANK) {
|
||||
/* Only set brightness if powered on or we get invalid/unsync state */
|
||||
ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL);
|
||||
}
|
||||
|
||||
/* Ensure brightness is stored to turn back on with */
|
||||
if (err == 0)
|
||||
asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct backlight_ops asus_screenpad_bl_ops = {
|
||||
.get_brightness = read_screenpad_brightness,
|
||||
.update_status = update_screenpad_bl_status,
|
||||
.options = BL_CORE_SUSPENDRESUME,
|
||||
};
|
||||
|
||||
static int asus_screenpad_init(struct asus_wmi *asus)
|
||||
{
|
||||
struct backlight_device *bd;
|
||||
struct backlight_properties props;
|
||||
int err, power;
|
||||
int brightness = 0;
|
||||
|
||||
power = read_screenpad_backlight_power(asus);
|
||||
if (power < 0)
|
||||
return power;
|
||||
|
||||
if (power != FB_BLANK_POWERDOWN) {
|
||||
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
/* default to an acceptable min brightness on boot if too low */
|
||||
if (brightness < ASUS_SCREENPAD_BRIGHT_MIN)
|
||||
brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */
|
||||
props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
bd = backlight_device_register("asus_screenpad",
|
||||
&asus->platform_device->dev, asus,
|
||||
&asus_screenpad_bl_ops, &props);
|
||||
if (IS_ERR(bd)) {
|
||||
pr_err("Could not register backlight device\n");
|
||||
return PTR_ERR(bd);
|
||||
}
|
||||
|
||||
asus->screenpad_backlight_device = bd;
|
||||
asus->driver->screenpad_brightness = brightness;
|
||||
bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN;
|
||||
bd->props.power = power;
|
||||
backlight_update_status(bd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void asus_screenpad_exit(struct asus_wmi *asus)
|
||||
{
|
||||
backlight_device_unregister(asus->screenpad_backlight_device);
|
||||
|
||||
asus->screenpad_backlight_device = NULL;
|
||||
}
|
||||
|
||||
/* Fn-lock ********************************************************************/
|
||||
|
||||
static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus)
|
||||
@ -4424,6 +4548,12 @@ static int asus_wmi_add(struct platform_device *pdev)
|
||||
} else if (asus->driver->quirks->wmi_backlight_set_devstate)
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
|
||||
|
||||
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT)) {
|
||||
err = asus_screenpad_init(asus);
|
||||
if (err && err != -ENODEV)
|
||||
goto fail_screenpad;
|
||||
}
|
||||
|
||||
if (asus_wmi_has_fnlock_key(asus)) {
|
||||
asus->fnlock_locked = fnlock_default;
|
||||
asus_wmi_fnlock_update(asus);
|
||||
@ -4447,6 +4577,8 @@ fail_wmi_handler:
|
||||
asus_wmi_backlight_exit(asus);
|
||||
fail_backlight:
|
||||
asus_wmi_rfkill_exit(asus);
|
||||
fail_screenpad:
|
||||
asus_screenpad_exit(asus);
|
||||
fail_rfkill:
|
||||
asus_wmi_led_exit(asus);
|
||||
fail_leds:
|
||||
@ -4473,6 +4605,7 @@ static int asus_wmi_remove(struct platform_device *device)
|
||||
asus = platform_get_drvdata(device);
|
||||
wmi_remove_notify_handler(asus->driver->event_guid);
|
||||
asus_wmi_backlight_exit(asus);
|
||||
asus_screenpad_exit(asus);
|
||||
asus_wmi_input_exit(asus);
|
||||
asus_wmi_led_exit(asus);
|
||||
asus_wmi_rfkill_exit(asus);
|
||||
|
@ -57,6 +57,7 @@ struct quirk_entry {
|
||||
struct asus_wmi_driver {
|
||||
int brightness;
|
||||
int panel_power;
|
||||
int screenpad_brightness;
|
||||
int wlan_ctrl_by_user;
|
||||
|
||||
const char *name;
|
||||
|
@ -19,7 +19,7 @@ struct bios_args {
|
||||
u32 command;
|
||||
u32 commandtype;
|
||||
u32 datasize;
|
||||
u8 data[];
|
||||
u8 data[] __counted_by(datasize);
|
||||
};
|
||||
|
||||
/**
|
||||
|
216
drivers/platform/x86/inspur_platform_profile.c
Normal file
216
drivers/platform/x86/inspur_platform_profile.c
Normal file
@ -0,0 +1,216 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Inspur WMI Platform Profile
|
||||
*
|
||||
* Copyright (C) 2018 Ai Chao <aichao@kylinos.cn>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_profile.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#define WMI_INSPUR_POWERMODE_BIOS_GUID "596C31E3-332D-43C9-AEE9-585493284F5D"
|
||||
|
||||
enum inspur_wmi_method_ids {
|
||||
INSPUR_WMI_GET_POWERMODE = 0x02,
|
||||
INSPUR_WMI_SET_POWERMODE = 0x03,
|
||||
};
|
||||
|
||||
/*
|
||||
* Power Mode:
|
||||
* 0x0: Balance Mode
|
||||
* 0x1: Performance Mode
|
||||
* 0x2: Power Saver Mode
|
||||
*/
|
||||
enum inspur_tmp_profile {
|
||||
INSPUR_TMP_PROFILE_BALANCE = 0,
|
||||
INSPUR_TMP_PROFILE_PERFORMANCE = 1,
|
||||
INSPUR_TMP_PROFILE_POWERSAVE = 2,
|
||||
};
|
||||
|
||||
struct inspur_wmi_priv {
|
||||
struct wmi_device *wdev;
|
||||
struct platform_profile_handler handler;
|
||||
};
|
||||
|
||||
static int inspur_wmi_perform_query(struct wmi_device *wdev,
|
||||
enum inspur_wmi_method_ids query_id,
|
||||
void *buffer, size_t insize,
|
||||
size_t outsize)
|
||||
{
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer input = { insize, buffer};
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
int ret = 0;
|
||||
|
||||
status = wmidev_evaluate_method(wdev, 0, query_id, &input, &output);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(&wdev->dev, "EC Powermode control failed: %s\n",
|
||||
acpi_format_exception(status));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
obj = output.pointer;
|
||||
if (!obj)
|
||||
return -EINVAL;
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER ||
|
||||
obj->buffer.length != outsize) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
memcpy(buffer, obj->buffer.pointer, obj->buffer.length);
|
||||
|
||||
out_free:
|
||||
kfree(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set Power Mode to EC RAM. If Power Mode value greater than 0x3,
|
||||
* return error
|
||||
* Method ID: 0x3
|
||||
* Arg: 4 Bytes
|
||||
* Byte [0]: Power Mode:
|
||||
* 0x0: Balance Mode
|
||||
* 0x1: Performance Mode
|
||||
* 0x2: Power Saver Mode
|
||||
* Return Value: 4 Bytes
|
||||
* Byte [0]: Return Code
|
||||
* 0x0: No Error
|
||||
* 0x1: Error
|
||||
*/
|
||||
static int inspur_platform_profile_set(struct platform_profile_handler *pprof,
|
||||
enum platform_profile_option profile)
|
||||
{
|
||||
struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv,
|
||||
handler);
|
||||
u8 ret_code[4] = {0, 0, 0, 0};
|
||||
int ret;
|
||||
|
||||
switch (profile) {
|
||||
case PLATFORM_PROFILE_BALANCED:
|
||||
ret_code[0] = INSPUR_TMP_PROFILE_BALANCE;
|
||||
break;
|
||||
case PLATFORM_PROFILE_PERFORMANCE:
|
||||
ret_code[0] = INSPUR_TMP_PROFILE_PERFORMANCE;
|
||||
break;
|
||||
case PLATFORM_PROFILE_LOW_POWER:
|
||||
ret_code[0] = INSPUR_TMP_PROFILE_POWERSAVE;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_SET_POWERMODE,
|
||||
ret_code, sizeof(ret_code),
|
||||
sizeof(ret_code));
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret_code[0])
|
||||
return -EBADRQC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Power Mode from EC RAM, If Power Mode value greater than 0x3,
|
||||
* return error
|
||||
* Method ID: 0x2
|
||||
* Return Value: 4 Bytes
|
||||
* Byte [0]: Return Code
|
||||
* 0x0: No Error
|
||||
* 0x1: Error
|
||||
* Byte [1]: Power Mode
|
||||
* 0x0: Balance Mode
|
||||
* 0x1: Performance Mode
|
||||
* 0x2: Power Saver Mode
|
||||
*/
|
||||
static int inspur_platform_profile_get(struct platform_profile_handler *pprof,
|
||||
enum platform_profile_option *profile)
|
||||
{
|
||||
struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv,
|
||||
handler);
|
||||
u8 ret_code[4] = {0, 0, 0, 0};
|
||||
int ret;
|
||||
|
||||
ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_GET_POWERMODE,
|
||||
&ret_code, sizeof(ret_code),
|
||||
sizeof(ret_code));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret_code[0])
|
||||
return -EBADRQC;
|
||||
|
||||
switch (ret_code[1]) {
|
||||
case INSPUR_TMP_PROFILE_BALANCE:
|
||||
*profile = PLATFORM_PROFILE_BALANCED;
|
||||
break;
|
||||
case INSPUR_TMP_PROFILE_PERFORMANCE:
|
||||
*profile = PLATFORM_PROFILE_PERFORMANCE;
|
||||
break;
|
||||
case INSPUR_TMP_PROFILE_POWERSAVE:
|
||||
*profile = PLATFORM_PROFILE_LOW_POWER;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inspur_wmi_probe(struct wmi_device *wdev, const void *context)
|
||||
{
|
||||
struct inspur_wmi_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->wdev = wdev;
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
|
||||
priv->handler.profile_get = inspur_platform_profile_get;
|
||||
priv->handler.profile_set = inspur_platform_profile_set;
|
||||
|
||||
set_bit(PLATFORM_PROFILE_LOW_POWER, priv->handler.choices);
|
||||
set_bit(PLATFORM_PROFILE_BALANCED, priv->handler.choices);
|
||||
set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->handler.choices);
|
||||
|
||||
return platform_profile_register(&priv->handler);
|
||||
}
|
||||
|
||||
static void inspur_wmi_remove(struct wmi_device *wdev)
|
||||
{
|
||||
platform_profile_remove();
|
||||
}
|
||||
|
||||
static const struct wmi_device_id inspur_wmi_id_table[] = {
|
||||
{ .guid_string = WMI_INSPUR_POWERMODE_BIOS_GUID },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(wmi, inspur_wmi_id_table);
|
||||
|
||||
static struct wmi_driver inspur_wmi_driver = {
|
||||
.driver = {
|
||||
.name = "inspur-wmi-platform-profile",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.id_table = inspur_wmi_id_table,
|
||||
.probe = inspur_wmi_probe,
|
||||
.remove = inspur_wmi_remove,
|
||||
};
|
||||
|
||||
module_wmi_driver(inspur_wmi_driver);
|
||||
|
||||
MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>");
|
||||
MODULE_DESCRIPTION("Platform Profile Support for Inspur");
|
||||
MODULE_LICENSE("GPL");
|
@ -158,17 +158,16 @@ static int crc_pwrsrc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crc_pwrsrc_remove(struct platform_device *pdev)
|
||||
static void crc_pwrsrc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct crc_pwrsrc_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
debugfs_remove_recursive(data->debug_dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver crc_pwrsrc_driver = {
|
||||
.probe = crc_pwrsrc_probe,
|
||||
.remove = crc_pwrsrc_remove,
|
||||
.remove_new = crc_pwrsrc_remove,
|
||||
.driver = {
|
||||
.name = "crystal_cove_pwrsrc",
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright(c) 2022 Intel Corporation. */
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/semaphore.h>
|
||||
@ -10,13 +11,16 @@
|
||||
|
||||
#include "ifs.h"
|
||||
|
||||
#define X86_MATCH(model) \
|
||||
#define X86_MATCH(model, array_gen) \
|
||||
X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \
|
||||
INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL)
|
||||
INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, array_gen)
|
||||
|
||||
static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
|
||||
X86_MATCH(SAPPHIRERAPIDS_X),
|
||||
X86_MATCH(EMERALDRAPIDS_X),
|
||||
X86_MATCH(SAPPHIRERAPIDS_X, ARRAY_GEN0),
|
||||
X86_MATCH(EMERALDRAPIDS_X, ARRAY_GEN0),
|
||||
X86_MATCH(GRANITERAPIDS_X, ARRAY_GEN0),
|
||||
X86_MATCH(GRANITERAPIDS_D, ARRAY_GEN0),
|
||||
X86_MATCH(ATOM_CRESTMONT_X, ARRAY_GEN1),
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);
|
||||
@ -94,6 +98,9 @@ static int __init ifs_init(void)
|
||||
for (i = 0; i < IFS_NUMTESTS; i++) {
|
||||
if (!(msrval & BIT(ifs_devices[i].test_caps->integrity_cap_bit)))
|
||||
continue;
|
||||
ifs_devices[i].rw_data.generation = FIELD_GET(MSR_INTEGRITY_CAPS_SAF_GEN_MASK,
|
||||
msrval);
|
||||
ifs_devices[i].rw_data.array_gen = (u32)m->driver_data;
|
||||
ret = misc_register(&ifs_devices[i].misc);
|
||||
if (ret)
|
||||
goto err_exit;
|
||||
|
@ -137,6 +137,10 @@
|
||||
#define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5
|
||||
#define MSR_ACTIVATE_SCAN 0x000002c6
|
||||
#define MSR_SCAN_STATUS 0x000002c7
|
||||
#define MSR_ARRAY_TRIGGER 0x000002d6
|
||||
#define MSR_ARRAY_STATUS 0x000002d7
|
||||
#define MSR_SAF_CTRL 0x000004f0
|
||||
|
||||
#define SCAN_NOT_TESTED 0
|
||||
#define SCAN_TEST_PASS 1
|
||||
#define SCAN_TEST_FAIL 2
|
||||
@ -144,6 +148,9 @@
|
||||
#define IFS_TYPE_SAF 0
|
||||
#define IFS_TYPE_ARRAY_BIST 1
|
||||
|
||||
#define ARRAY_GEN0 0
|
||||
#define ARRAY_GEN1 1
|
||||
|
||||
/* MSR_SCAN_HASHES_STATUS bit fields */
|
||||
union ifs_scan_hashes_status {
|
||||
u64 data;
|
||||
@ -158,6 +165,19 @@ union ifs_scan_hashes_status {
|
||||
};
|
||||
};
|
||||
|
||||
union ifs_scan_hashes_status_gen2 {
|
||||
u64 data;
|
||||
struct {
|
||||
u16 chunk_size;
|
||||
u16 num_chunks;
|
||||
u32 error_code :8;
|
||||
u32 chunks_in_stride :9;
|
||||
u32 rsvd :2;
|
||||
u32 max_core_limit :12;
|
||||
u32 valid :1;
|
||||
};
|
||||
};
|
||||
|
||||
/* MSR_CHUNKS_AUTH_STATUS bit fields */
|
||||
union ifs_chunks_auth_status {
|
||||
u64 data;
|
||||
@ -170,13 +190,31 @@ union ifs_chunks_auth_status {
|
||||
};
|
||||
};
|
||||
|
||||
union ifs_chunks_auth_status_gen2 {
|
||||
u64 data;
|
||||
struct {
|
||||
u16 valid_chunks;
|
||||
u16 total_chunks;
|
||||
u32 error_code :8;
|
||||
u32 rsvd2 :24;
|
||||
};
|
||||
};
|
||||
|
||||
/* MSR_ACTIVATE_SCAN bit fields */
|
||||
union ifs_scan {
|
||||
u64 data;
|
||||
struct {
|
||||
u32 start :8;
|
||||
u32 stop :8;
|
||||
u32 rsvd :16;
|
||||
union {
|
||||
struct {
|
||||
u8 start;
|
||||
u8 stop;
|
||||
u16 rsvd;
|
||||
} gen0;
|
||||
struct {
|
||||
u16 start;
|
||||
u16 stop;
|
||||
} gen2;
|
||||
};
|
||||
u32 delay :31;
|
||||
u32 sigmce :1;
|
||||
};
|
||||
@ -186,9 +224,17 @@ union ifs_scan {
|
||||
union ifs_status {
|
||||
u64 data;
|
||||
struct {
|
||||
u32 chunk_num :8;
|
||||
u32 chunk_stop_index :8;
|
||||
u32 rsvd1 :16;
|
||||
union {
|
||||
struct {
|
||||
u8 chunk_num;
|
||||
u8 chunk_stop_index;
|
||||
u16 rsvd1;
|
||||
} gen0;
|
||||
struct {
|
||||
u16 chunk_num;
|
||||
u16 chunk_stop_index;
|
||||
} gen2;
|
||||
};
|
||||
u32 error_code :8;
|
||||
u32 rsvd2 :22;
|
||||
u32 control_error :1;
|
||||
@ -229,6 +275,9 @@ struct ifs_test_caps {
|
||||
* @status: it holds simple status pass/fail/untested
|
||||
* @scan_details: opaque scan status code from h/w
|
||||
* @cur_batch: number indicating the currently loaded test file
|
||||
* @generation: IFS test generation enumerated by hardware
|
||||
* @chunk_size: size of a test chunk
|
||||
* @array_gen: test generation of array test
|
||||
*/
|
||||
struct ifs_data {
|
||||
int loaded_version;
|
||||
@ -238,6 +287,9 @@ struct ifs_data {
|
||||
int status;
|
||||
u64 scan_details;
|
||||
u32 cur_batch;
|
||||
u32 generation;
|
||||
u32 chunk_size;
|
||||
u32 array_gen;
|
||||
};
|
||||
|
||||
struct ifs_work {
|
||||
|
@ -2,6 +2,7 @@
|
||||
/* Copyright(c) 2022 Intel Corporation. */
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/microcode.h>
|
||||
|
||||
@ -26,6 +27,11 @@ union meta_data {
|
||||
|
||||
#define IFS_HEADER_SIZE (sizeof(struct microcode_header_intel))
|
||||
#define META_TYPE_IFS 1
|
||||
#define INVALIDATE_STRIDE 0x1UL
|
||||
#define IFS_GEN_STRIDE_AWARE 2
|
||||
#define AUTH_INTERRUPTED_ERROR 5
|
||||
#define IFS_AUTH_RETRY_CT 10
|
||||
|
||||
static struct microcode_header_intel *ifs_header_ptr; /* pointer to the ifs image header */
|
||||
static u64 ifs_hash_ptr; /* Address of ifs metadata (hash) */
|
||||
static u64 ifs_test_image_ptr; /* 256B aligned address of test pattern */
|
||||
@ -44,7 +50,10 @@ static const char * const scan_hash_status[] = {
|
||||
static const char * const scan_authentication_status[] = {
|
||||
[0] = "No error reported",
|
||||
[1] = "Attempt to authenticate a chunk which is already marked as authentic",
|
||||
[2] = "Chunk authentication error. The hash of chunk did not match expected value"
|
||||
[2] = "Chunk authentication error. The hash of chunk did not match expected value",
|
||||
[3] = "Reserved",
|
||||
[4] = "Chunk outside the current stride",
|
||||
[5] = "Authentication flow interrupted",
|
||||
};
|
||||
|
||||
#define MC_HEADER_META_TYPE_END (0)
|
||||
@ -80,6 +89,23 @@ static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_typ
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hashcopy_err_message(struct device *dev, u32 err_code)
|
||||
{
|
||||
if (err_code >= ARRAY_SIZE(scan_hash_status))
|
||||
dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
|
||||
else
|
||||
dev_err(dev, "Hash copy error : %s\n", scan_hash_status[err_code]);
|
||||
}
|
||||
|
||||
static void auth_err_message(struct device *dev, u32 err_code)
|
||||
{
|
||||
if (err_code >= ARRAY_SIZE(scan_authentication_status))
|
||||
dev_err(dev, "invalid error code 0x%x for authentication\n", err_code);
|
||||
else
|
||||
dev_err(dev, "Chunk authentication error : %s\n",
|
||||
scan_authentication_status[err_code]);
|
||||
}
|
||||
|
||||
/*
|
||||
* To copy scan hashes and authenticate test chunks, the initiating cpu must point
|
||||
* to the EDX:EAX to the test image in linear address.
|
||||
@ -109,11 +135,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)
|
||||
|
||||
if (!hashes_status.valid) {
|
||||
ifsd->loading_error = true;
|
||||
if (err_code >= ARRAY_SIZE(scan_hash_status)) {
|
||||
dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
|
||||
goto done;
|
||||
}
|
||||
dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]);
|
||||
hashcopy_err_message(dev, err_code);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -133,13 +155,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)
|
||||
|
||||
if (err_code) {
|
||||
ifsd->loading_error = true;
|
||||
if (err_code >= ARRAY_SIZE(scan_authentication_status)) {
|
||||
dev_err(dev,
|
||||
"invalid error code 0x%x for authentication\n", err_code);
|
||||
goto done;
|
||||
}
|
||||
dev_err(dev, "Chunk authentication error %s\n",
|
||||
scan_authentication_status[err_code]);
|
||||
auth_err_message(dev, err_code);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@ -147,6 +163,102 @@ done:
|
||||
complete(&ifs_done);
|
||||
}
|
||||
|
||||
static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status)
|
||||
{
|
||||
return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks;
|
||||
}
|
||||
|
||||
static bool need_copy_scan_hashes(struct ifs_data *ifsd)
|
||||
{
|
||||
return !ifsd->loaded ||
|
||||
ifsd->generation < IFS_GEN_STRIDE_AWARE ||
|
||||
ifsd->loaded_version != ifs_header_ptr->rev;
|
||||
}
|
||||
|
||||
static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
|
||||
{
|
||||
union ifs_scan_hashes_status_gen2 hashes_status;
|
||||
union ifs_chunks_auth_status_gen2 chunk_status;
|
||||
u32 err_code, valid_chunks, total_chunks;
|
||||
int i, num_chunks, chunk_size;
|
||||
union meta_data *ifs_meta;
|
||||
int starting_chunk_nr;
|
||||
struct ifs_data *ifsd;
|
||||
u64 linear_addr, base;
|
||||
u64 chunk_table[2];
|
||||
int retry_count;
|
||||
|
||||
ifsd = ifs_get_data(dev);
|
||||
|
||||
if (need_copy_scan_hashes(ifsd)) {
|
||||
wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
|
||||
rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
|
||||
|
||||
/* enumerate the scan image information */
|
||||
chunk_size = hashes_status.chunk_size * SZ_1K;
|
||||
err_code = hashes_status.error_code;
|
||||
|
||||
num_chunks = get_num_chunks(ifsd->generation, hashes_status);
|
||||
|
||||
if (!hashes_status.valid) {
|
||||
hashcopy_err_message(dev, err_code);
|
||||
return -EIO;
|
||||
}
|
||||
ifsd->loaded_version = ifs_header_ptr->rev;
|
||||
ifsd->chunk_size = chunk_size;
|
||||
} else {
|
||||
num_chunks = ifsd->valid_chunks;
|
||||
chunk_size = ifsd->chunk_size;
|
||||
}
|
||||
|
||||
if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) {
|
||||
wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE);
|
||||
rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
|
||||
if (chunk_status.valid_chunks != 0) {
|
||||
dev_err(dev, "Couldn't invalidate installed stride - %d\n",
|
||||
chunk_status.valid_chunks);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
base = ifs_test_image_ptr;
|
||||
ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS);
|
||||
starting_chunk_nr = ifs_meta->starting_chunk;
|
||||
|
||||
/* scan data authentication and copy chunks to secured memory */
|
||||
for (i = 0; i < num_chunks; i++) {
|
||||
retry_count = IFS_AUTH_RETRY_CT;
|
||||
linear_addr = base + i * chunk_size;
|
||||
|
||||
chunk_table[0] = starting_chunk_nr + i;
|
||||
chunk_table[1] = linear_addr;
|
||||
do {
|
||||
wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table);
|
||||
rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
|
||||
err_code = chunk_status.error_code;
|
||||
} while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count);
|
||||
|
||||
if (err_code) {
|
||||
ifsd->loading_error = true;
|
||||
auth_err_message(dev, err_code);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
valid_chunks = chunk_status.valid_chunks;
|
||||
total_chunks = chunk_status.total_chunks;
|
||||
|
||||
if (valid_chunks != total_chunks) {
|
||||
ifsd->loading_error = true;
|
||||
dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n",
|
||||
valid_chunks, total_chunks);
|
||||
return -EIO;
|
||||
}
|
||||
ifsd->valid_chunks = valid_chunks;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int validate_ifs_metadata(struct device *dev)
|
||||
{
|
||||
struct ifs_data *ifsd = ifs_get_data(dev);
|
||||
@ -179,6 +291,13 @@ static int validate_ifs_metadata(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ifs_meta->chunks_per_stride &&
|
||||
(ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) {
|
||||
dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n",
|
||||
ifs_meta->starting_chunk, ifs_meta->chunks_per_stride);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -199,7 +318,9 @@ static int scan_chunks_sanity_check(struct device *dev)
|
||||
return ret;
|
||||
|
||||
ifsd->loading_error = false;
|
||||
ifsd->loaded_version = ifs_header_ptr->rev;
|
||||
|
||||
if (ifsd->generation > 0)
|
||||
return copy_hashes_authenticate_chunks_gen2(dev);
|
||||
|
||||
/* copy the scan hash and authenticate per package */
|
||||
cpus_read_lock();
|
||||
@ -219,6 +340,7 @@ static int scan_chunks_sanity_check(struct device *dev)
|
||||
ifs_pkg_auth[curr_pkg] = 1;
|
||||
}
|
||||
ret = 0;
|
||||
ifsd->loaded_version = ifs_header_ptr->rev;
|
||||
out:
|
||||
cpus_read_unlock();
|
||||
|
||||
@ -260,6 +382,7 @@ int ifs_load_firmware(struct device *dev)
|
||||
{
|
||||
const struct ifs_test_caps *test = ifs_get_test_caps(dev);
|
||||
struct ifs_data *ifsd = ifs_get_data(dev);
|
||||
unsigned int expected_size;
|
||||
const struct firmware *fw;
|
||||
char scan_path[64];
|
||||
int ret = -EINVAL;
|
||||
@ -274,6 +397,13 @@ int ifs_load_firmware(struct device *dev)
|
||||
goto done;
|
||||
}
|
||||
|
||||
expected_size = ((struct microcode_header_intel *)fw->data)->totalsize;
|
||||
if (fw->size != expected_size) {
|
||||
dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n",
|
||||
expected_size, fw->size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data);
|
||||
if (ret)
|
||||
goto release;
|
||||
|
@ -40,6 +40,8 @@ enum ifs_status_err_code {
|
||||
IFS_UNASSIGNED_ERROR_CODE = 7,
|
||||
IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT = 8,
|
||||
IFS_INTERRUPTED_DURING_EXECUTION = 9,
|
||||
IFS_UNASSIGNED_ERROR_CODE_0xA = 0xA,
|
||||
IFS_CORRUPTED_CHUNK = 0xB,
|
||||
};
|
||||
|
||||
static const char * const scan_test_status[] = {
|
||||
@ -55,6 +57,8 @@ static const char * const scan_test_status[] = {
|
||||
[IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT] =
|
||||
"Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently",
|
||||
[IFS_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SCAN start",
|
||||
[IFS_UNASSIGNED_ERROR_CODE_0xA] = "Unassigned error code 0xA",
|
||||
[IFS_CORRUPTED_CHUNK] = "Scan operation aborted due to corrupted image. Try reloading",
|
||||
};
|
||||
|
||||
static void message_not_tested(struct device *dev, int cpu, union ifs_status status)
|
||||
@ -123,6 +127,8 @@ static bool can_restart(union ifs_status status)
|
||||
case IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS:
|
||||
case IFS_CORE_NOT_CAPABLE_CURRENTLY:
|
||||
case IFS_UNASSIGNED_ERROR_CODE:
|
||||
case IFS_UNASSIGNED_ERROR_CODE_0xA:
|
||||
case IFS_CORRUPTED_CHUNK:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
@ -171,21 +177,31 @@ static void ifs_test_core(int cpu, struct device *dev)
|
||||
union ifs_status status;
|
||||
unsigned long timeout;
|
||||
struct ifs_data *ifsd;
|
||||
int to_start, to_stop;
|
||||
int status_chunk;
|
||||
u64 msrvals[2];
|
||||
int retries;
|
||||
|
||||
ifsd = ifs_get_data(dev);
|
||||
|
||||
activate.rsvd = 0;
|
||||
activate.gen0.rsvd = 0;
|
||||
activate.delay = IFS_THREAD_WAIT;
|
||||
activate.sigmce = 0;
|
||||
activate.start = 0;
|
||||
activate.stop = ifsd->valid_chunks - 1;
|
||||
to_start = 0;
|
||||
to_stop = ifsd->valid_chunks - 1;
|
||||
|
||||
if (ifsd->generation) {
|
||||
activate.gen2.start = to_start;
|
||||
activate.gen2.stop = to_stop;
|
||||
} else {
|
||||
activate.gen0.start = to_start;
|
||||
activate.gen0.stop = to_stop;
|
||||
}
|
||||
|
||||
timeout = jiffies + HZ / 2;
|
||||
retries = MAX_IFS_RETRIES;
|
||||
|
||||
while (activate.start <= activate.stop) {
|
||||
while (to_start <= to_stop) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
status.error_code = IFS_SW_TIMEOUT;
|
||||
break;
|
||||
@ -196,13 +212,14 @@ static void ifs_test_core(int cpu, struct device *dev)
|
||||
|
||||
status.data = msrvals[1];
|
||||
|
||||
trace_ifs_status(cpu, activate, status);
|
||||
trace_ifs_status(cpu, to_start, to_stop, status.data);
|
||||
|
||||
/* Some cases can be retried, give up for others */
|
||||
if (!can_restart(status))
|
||||
break;
|
||||
|
||||
if (status.chunk_num == activate.start) {
|
||||
status_chunk = ifsd->generation ? status.gen2.chunk_num : status.gen0.chunk_num;
|
||||
if (status_chunk == to_start) {
|
||||
/* Check for forward progress */
|
||||
if (--retries == 0) {
|
||||
if (status.error_code == IFS_NO_ERROR)
|
||||
@ -211,7 +228,11 @@ static void ifs_test_core(int cpu, struct device *dev)
|
||||
}
|
||||
} else {
|
||||
retries = MAX_IFS_RETRIES;
|
||||
activate.start = status.chunk_num;
|
||||
if (ifsd->generation)
|
||||
activate.gen2.start = status_chunk;
|
||||
else
|
||||
activate.gen0.start = status_chunk;
|
||||
to_start = status_chunk;
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,6 +329,38 @@ static void ifs_array_test_core(int cpu, struct device *dev)
|
||||
ifsd->status = SCAN_TEST_PASS;
|
||||
}
|
||||
|
||||
#define ARRAY_GEN1_TEST_ALL_ARRAYS 0x0ULL
|
||||
#define ARRAY_GEN1_STATUS_FAIL 0x1ULL
|
||||
|
||||
static int do_array_test_gen1(void *status)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
int first;
|
||||
|
||||
first = cpumask_first(cpu_smt_mask(cpu));
|
||||
|
||||
if (cpu == first) {
|
||||
wrmsrl(MSR_ARRAY_TRIGGER, ARRAY_GEN1_TEST_ALL_ARRAYS);
|
||||
rdmsrl(MSR_ARRAY_STATUS, *((u64 *)status));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ifs_array_test_gen1(int cpu, struct device *dev)
|
||||
{
|
||||
struct ifs_data *ifsd = ifs_get_data(dev);
|
||||
u64 status = 0;
|
||||
|
||||
stop_core_cpuslocked(cpu, do_array_test_gen1, &status);
|
||||
ifsd->scan_details = status;
|
||||
|
||||
if (status & ARRAY_GEN1_STATUS_FAIL)
|
||||
ifsd->status = SCAN_TEST_FAIL;
|
||||
else
|
||||
ifsd->status = SCAN_TEST_PASS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate per core test. It wakes up work queue threads on the target cpu and
|
||||
* its sibling cpu. Once all sibling threads wake up, the scan test gets executed and
|
||||
@ -336,7 +389,10 @@ int do_core_test(int cpu, struct device *dev)
|
||||
ifs_test_core(cpu, dev);
|
||||
break;
|
||||
case IFS_TYPE_ARRAY_BIST:
|
||||
ifs_array_test_core(cpu, dev);
|
||||
if (ifsd->array_gen == ARRAY_GEN0)
|
||||
ifs_array_test_core(cpu, dev);
|
||||
else
|
||||
ifs_array_test_gen1(cpu, dev);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -18,16 +18,17 @@
|
||||
struct isst_mmio_range {
|
||||
int beg;
|
||||
int end;
|
||||
int size;
|
||||
};
|
||||
|
||||
static struct isst_mmio_range mmio_range_devid_0[] = {
|
||||
{0x04, 0x14},
|
||||
{0x20, 0xD0},
|
||||
{0x04, 0x14, 0x18},
|
||||
{0x20, 0xD0, 0xD4},
|
||||
};
|
||||
|
||||
static struct isst_mmio_range mmio_range_devid_1[] = {
|
||||
{0x04, 0x14},
|
||||
{0x20, 0x11C},
|
||||
{0x04, 0x14, 0x18},
|
||||
{0x20, 0x11C, 0x120},
|
||||
};
|
||||
|
||||
struct isst_if_device {
|
||||
@ -93,6 +94,7 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
struct isst_if_device *punit_dev;
|
||||
struct isst_if_cmd_cb cb;
|
||||
u32 mmio_base, pcu_base;
|
||||
struct resource r;
|
||||
u64 base_addr;
|
||||
int ret;
|
||||
|
||||
@ -114,13 +116,16 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
pcu_base &= GENMASK(10, 0);
|
||||
base_addr = (u64)mmio_base << 23 | (u64) pcu_base << 12;
|
||||
punit_dev->punit_mmio = devm_ioremap(&pdev->dev, base_addr, 256);
|
||||
if (!punit_dev->punit_mmio)
|
||||
return -ENOMEM;
|
||||
|
||||
punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data;
|
||||
|
||||
r = DEFINE_RES_MEM(base_addr, punit_dev->mmio_range[1].size);
|
||||
punit_dev->punit_mmio = devm_ioremap_resource(&pdev->dev, &r);
|
||||
if (IS_ERR(punit_dev->punit_mmio))
|
||||
return PTR_ERR(punit_dev->punit_mmio);
|
||||
|
||||
mutex_init(&punit_dev->mutex);
|
||||
pci_set_drvdata(pdev, punit_dev);
|
||||
punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data;
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
cb.cmd_size = sizeof(struct isst_if_io_reg);
|
||||
|
@ -30,7 +30,8 @@
|
||||
#include "isst_if_common.h"
|
||||
|
||||
/* Supported SST hardware version by this driver */
|
||||
#define ISST_HEADER_VERSION 1
|
||||
#define ISST_MAJOR_VERSION 0
|
||||
#define ISST_MINOR_VERSION 1
|
||||
|
||||
/*
|
||||
* Used to indicate if value read from MMIO needs to get multiplied
|
||||
@ -352,21 +353,25 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai
|
||||
pd_info->sst_header.cp_offset *= 8;
|
||||
pd_info->sst_header.pp_offset *= 8;
|
||||
|
||||
if (pd_info->sst_header.interface_version != ISST_HEADER_VERSION) {
|
||||
dev_err(&auxdev->dev, "SST: Unsupported version:%x\n",
|
||||
pd_info->sst_header.interface_version);
|
||||
if (pd_info->sst_header.interface_version == TPMI_VERSION_INVALID)
|
||||
return -ENODEV;
|
||||
|
||||
if (TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version) != ISST_MAJOR_VERSION) {
|
||||
dev_err(&auxdev->dev, "SST: Unsupported major version:%lx\n",
|
||||
TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) != ISST_MINOR_VERSION)
|
||||
dev_info(&auxdev->dev, "SST: Ignore: Unsupported minor version:%lx\n",
|
||||
TPMI_MINOR_VERSION(pd_info->sst_header.interface_version));
|
||||
|
||||
/* Read SST CP Header */
|
||||
*((u64 *)&pd_info->cp_header) = readq(pd_info->sst_base + pd_info->sst_header.cp_offset);
|
||||
|
||||
/* Read PP header */
|
||||
*((u64 *)&pd_info->pp_header) = readq(pd_info->sst_base + pd_info->sst_header.pp_offset);
|
||||
|
||||
/* Force level_en_mask level 0 */
|
||||
pd_info->pp_header.level_en_mask |= 0x01;
|
||||
|
||||
mask = 0x01;
|
||||
levels = 0;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
@ -704,7 +709,7 @@ static int isst_if_get_perf_level(void __user *argp)
|
||||
return -EINVAL;
|
||||
|
||||
perf_level.max_level = power_domain_info->max_level;
|
||||
perf_level.level_mask = power_domain_info->pp_header.allowed_level_mask;
|
||||
perf_level.level_mask = power_domain_info->pp_header.level_en_mask;
|
||||
perf_level.feature_rev = power_domain_info->pp_header.feature_rev;
|
||||
_read_pp_info("current_level", perf_level.current_level, SST_PP_STATUS_OFFSET,
|
||||
SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
|
||||
|
@ -143,6 +143,33 @@ struct tpmi_info_header {
|
||||
u64 lock:1;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct tpmi_feature_state - Structure to read hardware state of a feature
|
||||
* @enabled: Enable state of a feature, 1: enabled, 0: disabled
|
||||
* @reserved_1: Reserved for future use
|
||||
* @write_blocked: Writes are blocked means all write operations are ignored
|
||||
* @read_blocked: Reads are blocked means will read 0xFFs
|
||||
* @pcs_select: Interface used by out of band software, not used in OS
|
||||
* @reserved_2: Reserved for future use
|
||||
* @id: TPMI ID of the feature
|
||||
* @reserved_3: Reserved for future use
|
||||
* @locked: When set to 1, OS can't change this register.
|
||||
*
|
||||
* The structure is used to read hardware state of a TPMI feature. This
|
||||
* information is used for debug and restricting operations for this feature.
|
||||
*/
|
||||
struct tpmi_feature_state {
|
||||
u32 enabled:1;
|
||||
u32 reserved_1:3;
|
||||
u32 write_blocked:1;
|
||||
u32 read_blocked:1;
|
||||
u32 pcs_select:1;
|
||||
u32 reserved_2:1;
|
||||
u32 id:8;
|
||||
u32 reserved_3:15;
|
||||
u32 locked:1;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* List of supported TMPI IDs.
|
||||
* Some TMPI IDs are not used by Linux, so the numbers are not consecutive.
|
||||
@ -202,6 +229,7 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
|
||||
|
||||
#define TPMI_CONTROL_STATUS_OFFSET 0x00
|
||||
#define TPMI_COMMAND_OFFSET 0x08
|
||||
#define TMPI_CONTROL_DATA_VAL_OFFSET 0x0c
|
||||
|
||||
/*
|
||||
* Spec is calling for max 1 seconds to get ownership at the worst
|
||||
@ -230,7 +258,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
|
||||
|
||||
/* TPMI command data registers */
|
||||
#define TMPI_CONTROL_DATA_CMD GENMASK_ULL(7, 0)
|
||||
#define TMPI_CONTROL_DATA_VAL GENMASK_ULL(63, 32)
|
||||
#define TPMI_CONTROL_DATA_VAL_FEATURE GENMASK_ULL(48, 40)
|
||||
|
||||
/* Command to send via control interface */
|
||||
@ -240,9 +267,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
|
||||
|
||||
#define TPMI_CMD_LEN_MASK GENMASK_ULL(18, 16)
|
||||
|
||||
#define TPMI_STATE_DISABLED BIT_ULL(0)
|
||||
#define TPMI_STATE_LOCKED BIT_ULL(31)
|
||||
|
||||
/* Mutex to complete get feature status without interruption */
|
||||
static DEFINE_MUTEX(tpmi_dev_lock);
|
||||
|
||||
@ -256,7 +280,7 @@ static int tpmi_wait_for_owner(struct intel_tpmi_info *tpmi_info, u8 owner)
|
||||
}
|
||||
|
||||
static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int feature_id,
|
||||
int *locked, int *disabled)
|
||||
struct tpmi_feature_state *feature_state)
|
||||
{
|
||||
u64 control, data;
|
||||
int ret;
|
||||
@ -306,17 +330,8 @@ static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int featu
|
||||
}
|
||||
|
||||
/* Response is ready */
|
||||
data = readq(tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET);
|
||||
data = FIELD_GET(TMPI_CONTROL_DATA_VAL, data);
|
||||
|
||||
*disabled = 0;
|
||||
*locked = 0;
|
||||
|
||||
if (!(data & TPMI_STATE_DISABLED))
|
||||
*disabled = 1;
|
||||
|
||||
if (data & TPMI_STATE_LOCKED)
|
||||
*locked = 1;
|
||||
memcpy_fromio(feature_state, tpmi_info->tpmi_control_mem + TMPI_CONTROL_DATA_VAL_OFFSET,
|
||||
sizeof(*feature_state));
|
||||
|
||||
ret = 0;
|
||||
|
||||
@ -335,34 +350,50 @@ int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id,
|
||||
{
|
||||
struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent);
|
||||
struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev);
|
||||
struct tpmi_feature_state feature_state;
|
||||
int ret;
|
||||
|
||||
return tpmi_read_feature_status(tpmi_info, feature_id, locked, disabled);
|
||||
ret = tpmi_read_feature_status(tpmi_info, feature_id, &feature_state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*locked = feature_state.locked;
|
||||
*disabled = !feature_state.enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI);
|
||||
|
||||
static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct intel_tpmi_info *tpmi_info = s->private;
|
||||
int locked, disabled, read_blocked, write_blocked;
|
||||
struct tpmi_feature_state feature_state;
|
||||
struct intel_tpmi_pm_feature *pfs;
|
||||
int locked, disabled, ret, i;
|
||||
int ret, i;
|
||||
|
||||
|
||||
seq_printf(s, "tpmi PFS start offset 0x:%llx\n", tpmi_info->pfs_start);
|
||||
seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\n");
|
||||
seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\tread_blocked\twrite_blocked\n");
|
||||
for (i = 0; i < tpmi_info->feature_count; ++i) {
|
||||
pfs = &tpmi_info->tpmi_features[i];
|
||||
ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &locked,
|
||||
&disabled);
|
||||
ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state);
|
||||
if (ret) {
|
||||
locked = 'U';
|
||||
disabled = 'U';
|
||||
read_blocked = 'U';
|
||||
write_blocked = 'U';
|
||||
} else {
|
||||
disabled = disabled ? 'Y' : 'N';
|
||||
locked = locked ? 'Y' : 'N';
|
||||
disabled = feature_state.enabled ? 'N' : 'Y';
|
||||
locked = feature_state.locked ? 'Y' : 'N';
|
||||
read_blocked = feature_state.read_blocked ? 'Y' : 'N';
|
||||
write_blocked = feature_state.write_blocked ? 'Y' : 'N';
|
||||
}
|
||||
seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\n",
|
||||
seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\t\t%c\t\t%c\n",
|
||||
pfs->pfs_header.tpmi_id, pfs->pfs_header.num_entries,
|
||||
pfs->pfs_header.entry_size, pfs->pfs_header.cap_offset,
|
||||
pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled);
|
||||
pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled,
|
||||
read_blocked, write_blocked);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -28,7 +28,8 @@
|
||||
|
||||
#include "uncore-frequency-common.h"
|
||||
|
||||
#define UNCORE_HEADER_VERSION 1
|
||||
#define UNCORE_MAJOR_VERSION 0
|
||||
#define UNCORE_MINOR_VERSION 1
|
||||
#define UNCORE_HEADER_INDEX 0
|
||||
#define UNCORE_FABRIC_CLUSTER_OFFSET 8
|
||||
|
||||
@ -302,12 +303,21 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
|
||||
/* Check for version and skip this resource if there is mismatch */
|
||||
header = readq(pd_info->uncore_base);
|
||||
pd_info->ufs_header_ver = header & UNCORE_VERSION_MASK;
|
||||
if (pd_info->ufs_header_ver != UNCORE_HEADER_VERSION) {
|
||||
dev_info(&auxdev->dev, "Uncore: Unsupported version:%d\n",
|
||||
pd_info->ufs_header_ver);
|
||||
|
||||
if (pd_info->ufs_header_ver == TPMI_VERSION_INVALID)
|
||||
continue;
|
||||
|
||||
if (TPMI_MAJOR_VERSION(pd_info->ufs_header_ver) != UNCORE_MAJOR_VERSION) {
|
||||
dev_err(&auxdev->dev, "Uncore: Unsupported major version:%lx\n",
|
||||
TPMI_MAJOR_VERSION(pd_info->ufs_header_ver));
|
||||
ret = -ENODEV;
|
||||
goto remove_clusters;
|
||||
}
|
||||
|
||||
if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) != UNCORE_MINOR_VERSION)
|
||||
dev_info(&auxdev->dev, "Uncore: Ignore: Unsupported minor version:%lx\n",
|
||||
TPMI_MINOR_VERSION(pd_info->ufs_header_ver));
|
||||
|
||||
/* Get Cluster ID Mask */
|
||||
cluster_mask = FIELD_GET(UNCORE_LOCAL_FABRIC_CLUSTER_ID_MASK, header);
|
||||
if (!cluster_mask) {
|
||||
|
@ -368,7 +368,7 @@ struct mlxplat_priv {
|
||||
};
|
||||
|
||||
static struct platform_device *mlxplat_dev;
|
||||
static int mlxplat_i2c_main_complition_notify(void *handle, int id);
|
||||
static int mlxplat_i2c_main_completion_notify(void *handle, int id);
|
||||
static void __iomem *i2c_bridge_addr, *jtag_bridge_addr;
|
||||
|
||||
/* Regions for LPC I2C controller and LPC base register space */
|
||||
@ -384,7 +384,7 @@ static const struct resource mlxplat_lpc_resources[] = {
|
||||
|
||||
/* Platform systems default i2c data */
|
||||
static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_default_data = {
|
||||
.completion_notify = mlxplat_i2c_main_complition_notify,
|
||||
.completion_notify = mlxplat_i2c_main_completion_notify,
|
||||
};
|
||||
|
||||
/* Platform i2c next generation systems data */
|
||||
@ -409,7 +409,7 @@ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = {
|
||||
.mask = MLXPLAT_CPLD_AGGR_MASK_COMEX,
|
||||
.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET,
|
||||
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C,
|
||||
.completion_notify = mlxplat_i2c_main_complition_notify,
|
||||
.completion_notify = mlxplat_i2c_main_completion_notify,
|
||||
};
|
||||
|
||||
/* Platform default channels */
|
||||
@ -6291,7 +6291,7 @@ static void mlxplat_pci_fpga_devices_exit(void)
|
||||
}
|
||||
|
||||
static int
|
||||
mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size)
|
||||
mlxplat_logicdev_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
@ -6302,7 +6302,7 @@ mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_reso
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlxplat_post_exit(void)
|
||||
static void mlxplat_logicdev_exit(void)
|
||||
{
|
||||
if (lpc_bridge)
|
||||
mlxplat_pci_fpga_devices_exit();
|
||||
@ -6310,7 +6310,7 @@ static void mlxplat_post_exit(void)
|
||||
mlxplat_lpc_cpld_device_exit();
|
||||
}
|
||||
|
||||
static int mlxplat_post_init(struct mlxplat_priv *priv)
|
||||
static int mlxplat_platdevs_init(struct mlxplat_priv *priv)
|
||||
{
|
||||
int i = 0, err;
|
||||
|
||||
@ -6407,7 +6407,7 @@ fail_platform_hotplug_register:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlxplat_pre_exit(struct mlxplat_priv *priv)
|
||||
static void mlxplat_platdevs_exit(struct mlxplat_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -6429,7 +6429,7 @@ mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent,
|
||||
{
|
||||
struct mlxplat_priv *priv = handle;
|
||||
|
||||
return mlxplat_post_init(priv);
|
||||
return mlxplat_platdevs_init(priv);
|
||||
}
|
||||
|
||||
static int mlxplat_i2c_mux_topology_init(struct mlxplat_priv *priv)
|
||||
@ -6471,7 +6471,7 @@ static void mlxplat_i2c_mux_topology_exit(struct mlxplat_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
static int mlxplat_i2c_main_complition_notify(void *handle, int id)
|
||||
static int mlxplat_i2c_main_completion_notify(void *handle, int id)
|
||||
{
|
||||
struct mlxplat_priv *priv = handle;
|
||||
|
||||
@ -6522,7 +6522,7 @@ fail_mlxplat_mlxcpld_verify_bus_topology:
|
||||
|
||||
static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv)
|
||||
{
|
||||
mlxplat_pre_exit(priv);
|
||||
mlxplat_platdevs_exit(priv);
|
||||
mlxplat_i2c_mux_topology_exit(priv);
|
||||
if (priv->pdev_i2c)
|
||||
platform_device_unregister(priv->pdev_i2c);
|
||||
@ -6544,7 +6544,7 @@ static int mlxplat_probe(struct platform_device *pdev)
|
||||
mlxplat_dev = pdev;
|
||||
}
|
||||
|
||||
err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size);
|
||||
err = mlxplat_logicdev_init(&hotplug_resources, &hotplug_resources_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -6603,12 +6603,12 @@ fail_regcache_sync:
|
||||
fail_mlxplat_i2c_main_init:
|
||||
fail_regmap_write:
|
||||
fail_alloc:
|
||||
mlxplat_post_exit();
|
||||
mlxplat_logicdev_exit();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlxplat_remove(struct platform_device *pdev)
|
||||
static void mlxplat_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
|
||||
|
||||
@ -6617,8 +6617,7 @@ static int mlxplat_remove(struct platform_device *pdev)
|
||||
if (mlxplat_reboot_nb)
|
||||
unregister_reboot_notifier(mlxplat_reboot_nb);
|
||||
mlxplat_i2c_main_exit(priv);
|
||||
mlxplat_post_exit();
|
||||
return 0;
|
||||
mlxplat_logicdev_exit();
|
||||
}
|
||||
|
||||
static const struct acpi_device_id mlxplat_acpi_table[] = {
|
||||
@ -6634,7 +6633,7 @@ static struct platform_driver mlxplat_driver = {
|
||||
.probe_type = PROBE_FORCE_SYNCHRONOUS,
|
||||
},
|
||||
.probe = mlxplat_probe,
|
||||
.remove = mlxplat_remove,
|
||||
.remove_new = mlxplat_remove,
|
||||
};
|
||||
|
||||
static int __init mlxplat_init(void)
|
||||
|
@ -58,7 +58,7 @@ static struct msi_ec_conf CONF0 __initdata = {
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_super_swap = {
|
||||
.fn_win_swap = {
|
||||
.address = 0xbf,
|
||||
.bit = 4,
|
||||
},
|
||||
@ -138,7 +138,7 @@ static struct msi_ec_conf CONF1 __initdata = {
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_super_swap = {
|
||||
.fn_win_swap = {
|
||||
.address = 0xbf,
|
||||
.bit = 4,
|
||||
},
|
||||
@ -215,7 +215,7 @@ static struct msi_ec_conf CONF2 __initdata = {
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_super_swap = {
|
||||
.fn_win_swap = {
|
||||
.address = 0xe8,
|
||||
.bit = 4,
|
||||
},
|
||||
@ -293,7 +293,7 @@ static struct msi_ec_conf CONF3 __initdata = {
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_super_swap = {
|
||||
.fn_win_swap = {
|
||||
.address = 0xe8,
|
||||
.bit = 4,
|
||||
},
|
||||
@ -371,7 +371,7 @@ static struct msi_ec_conf CONF4 __initdata = {
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_super_swap = {
|
||||
.fn_win_swap = {
|
||||
.address = MSI_EC_ADDR_UNKNOWN, // supported, but unknown
|
||||
.bit = 4,
|
||||
},
|
||||
@ -450,7 +450,7 @@ static struct msi_ec_conf CONF5 __initdata = {
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_super_swap = { // todo: reverse
|
||||
.fn_win_swap = { // todo: reverse
|
||||
.address = 0xbf,
|
||||
.bit = 4,
|
||||
},
|
||||
@ -528,7 +528,7 @@ static struct msi_ec_conf CONF6 __initdata = {
|
||||
.block_address = MSI_EC_ADDR_UNSUPP,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_super_swap = {
|
||||
.fn_win_swap = {
|
||||
.address = 0xbf, // todo: reverse
|
||||
.bit = 4,
|
||||
},
|
||||
@ -608,7 +608,7 @@ static struct msi_ec_conf CONF7 __initdata = {
|
||||
.block_address = MSI_EC_ADDR_UNSUPP,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_super_swap = {
|
||||
.fn_win_swap = {
|
||||
.address = 0xbf, // needs testing
|
||||
.bit = 4,
|
||||
},
|
||||
@ -667,6 +667,467 @@ static struct msi_ec_conf CONF7 __initdata = {
|
||||
},
|
||||
};
|
||||
|
||||
static const char * const ALLOWED_FW_8[] __initconst = {
|
||||
"14F1EMS1.115",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct msi_ec_conf CONF8 __initdata = {
|
||||
.allowed_fw = ALLOWED_FW_8,
|
||||
.charge_control = {
|
||||
.address = 0xd7,
|
||||
.offset_start = 0x8a,
|
||||
.offset_end = 0x80,
|
||||
.range_min = 0x8a,
|
||||
.range_max = 0xe4,
|
||||
},
|
||||
.webcam = {
|
||||
.address = 0x2e,
|
||||
.block_address = MSI_EC_ADDR_UNSUPP,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_win_swap = {
|
||||
.address = 0xe8,
|
||||
.bit = 4,
|
||||
},
|
||||
.cooler_boost = {
|
||||
.address = 0x98,
|
||||
.bit = 7,
|
||||
},
|
||||
.shift_mode = {
|
||||
.address = 0xd2,
|
||||
.modes = {
|
||||
{ SM_ECO_NAME, 0xc2 },
|
||||
{ SM_COMFORT_NAME, 0xc1 },
|
||||
{ SM_SPORT_NAME, 0xc0 },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.super_battery = {
|
||||
.address = 0xeb,
|
||||
.mask = 0x0f,
|
||||
},
|
||||
.fan_mode = {
|
||||
.address = 0xd4,
|
||||
.modes = {
|
||||
{ FM_AUTO_NAME, 0x0d },
|
||||
{ FM_SILENT_NAME, 0x1d },
|
||||
{ FM_BASIC_NAME, 0x4d },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.cpu = {
|
||||
.rt_temp_address = 0x68,
|
||||
.rt_fan_speed_address = 0x71,
|
||||
.rt_fan_speed_base_min = 0x19,
|
||||
.rt_fan_speed_base_max = 0x37,
|
||||
.bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
|
||||
.bs_fan_speed_base_min = 0x00,
|
||||
.bs_fan_speed_base_max = 0x0f,
|
||||
},
|
||||
.gpu = {
|
||||
.rt_temp_address = MSI_EC_ADDR_UNKNOWN,
|
||||
.rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
|
||||
},
|
||||
.leds = {
|
||||
.micmute_led_address = MSI_EC_ADDR_UNSUPP,
|
||||
.mute_led_address = 0x2d,
|
||||
.bit = 1,
|
||||
},
|
||||
.kbd_bl = {
|
||||
.bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
|
||||
.bl_modes = { 0x00, 0x08 }, // ?
|
||||
.max_mode = 1, // ?
|
||||
.bl_state_address = MSI_EC_ADDR_UNSUPP, // not functional
|
||||
.state_base_value = 0x80,
|
||||
.max_state = 3,
|
||||
},
|
||||
};
|
||||
|
||||
static const char * const ALLOWED_FW_9[] __initconst = {
|
||||
"14JKEMS1.104",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct msi_ec_conf CONF9 __initdata = {
|
||||
.allowed_fw = ALLOWED_FW_9,
|
||||
.charge_control = {
|
||||
.address = 0xef,
|
||||
.offset_start = 0x8a,
|
||||
.offset_end = 0x80,
|
||||
.range_min = 0x8a,
|
||||
.range_max = 0xe4,
|
||||
},
|
||||
.webcam = {
|
||||
.address = 0x2e,
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_win_swap = {
|
||||
.address = 0xbf,
|
||||
.bit = 4,
|
||||
},
|
||||
.cooler_boost = {
|
||||
.address = 0x98,
|
||||
.bit = 7,
|
||||
},
|
||||
.shift_mode = {
|
||||
.address = 0xf2,
|
||||
.modes = {
|
||||
{ SM_ECO_NAME, 0xc2 },
|
||||
{ SM_COMFORT_NAME, 0xc1 },
|
||||
{ SM_SPORT_NAME, 0xc0 },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.super_battery = {
|
||||
.address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift
|
||||
.mask = 0x0f,
|
||||
},
|
||||
.fan_mode = {
|
||||
.address = 0xf4,
|
||||
.modes = {
|
||||
{ FM_AUTO_NAME, 0x0d },
|
||||
{ FM_SILENT_NAME, 0x1d },
|
||||
{ FM_ADVANCED_NAME, 0x8d },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.cpu = {
|
||||
.rt_temp_address = 0x68,
|
||||
.rt_fan_speed_address = 0x71,
|
||||
.rt_fan_speed_base_min = 0x00,
|
||||
.rt_fan_speed_base_max = 0x96,
|
||||
.bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
|
||||
.bs_fan_speed_base_min = 0x00,
|
||||
.bs_fan_speed_base_max = 0x0f,
|
||||
},
|
||||
.gpu = {
|
||||
.rt_temp_address = MSI_EC_ADDR_UNSUPP,
|
||||
.rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
|
||||
},
|
||||
.leds = {
|
||||
.micmute_led_address = 0x2b,
|
||||
.mute_led_address = 0x2c,
|
||||
.bit = 2,
|
||||
},
|
||||
.kbd_bl = {
|
||||
.bl_mode_address = MSI_EC_ADDR_UNSUPP, // not presented in MSI app
|
||||
.bl_modes = { 0x00, 0x08 },
|
||||
.max_mode = 1,
|
||||
.bl_state_address = 0xf3,
|
||||
.state_base_value = 0x80,
|
||||
.max_state = 3,
|
||||
},
|
||||
};
|
||||
|
||||
static const char * const ALLOWED_FW_10[] __initconst = {
|
||||
"1582EMS1.107", // GF66 11UC
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct msi_ec_conf CONF10 __initdata = {
|
||||
.allowed_fw = ALLOWED_FW_10,
|
||||
.charge_control = {
|
||||
.address = 0xd7,
|
||||
.offset_start = 0x8a,
|
||||
.offset_end = 0x80,
|
||||
.range_min = 0x8a,
|
||||
.range_max = 0xe4,
|
||||
},
|
||||
.webcam = {
|
||||
.address = 0x2e,
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_win_swap = {
|
||||
.address = MSI_EC_ADDR_UNSUPP,
|
||||
.bit = 4,
|
||||
},
|
||||
.cooler_boost = {
|
||||
.address = 0x98,
|
||||
.bit = 7,
|
||||
},
|
||||
.shift_mode = {
|
||||
.address = 0xd2,
|
||||
.modes = {
|
||||
{ SM_ECO_NAME, 0xc2 },
|
||||
{ SM_COMFORT_NAME, 0xc1 },
|
||||
{ SM_SPORT_NAME, 0xc0 },
|
||||
{ SM_TURBO_NAME, 0xc4 },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.super_battery = {
|
||||
.address = 0xe5,
|
||||
.mask = 0x0f,
|
||||
},
|
||||
.fan_mode = {
|
||||
.address = 0xd4,
|
||||
.modes = {
|
||||
{ FM_AUTO_NAME, 0x0d },
|
||||
{ FM_SILENT_NAME, 0x1d },
|
||||
{ FM_ADVANCED_NAME, 0x8d },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.cpu = {
|
||||
.rt_temp_address = 0x68,
|
||||
.rt_fan_speed_address = 0x71, // ?
|
||||
.rt_fan_speed_base_min = 0x19,
|
||||
.rt_fan_speed_base_max = 0x37,
|
||||
.bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, // ?
|
||||
.bs_fan_speed_base_min = 0x00,
|
||||
.bs_fan_speed_base_max = 0x0f,
|
||||
},
|
||||
.gpu = {
|
||||
.rt_temp_address = 0x80,
|
||||
.rt_fan_speed_address = 0x89,
|
||||
},
|
||||
.leds = {
|
||||
.micmute_led_address = 0x2c,
|
||||
.mute_led_address = 0x2d,
|
||||
.bit = 1,
|
||||
},
|
||||
.kbd_bl = {
|
||||
.bl_mode_address = 0x2c,
|
||||
.bl_modes = { 0x00, 0x08 },
|
||||
.max_mode = 1,
|
||||
.bl_state_address = 0xd3,
|
||||
.state_base_value = 0x80,
|
||||
.max_state = 3,
|
||||
},
|
||||
};
|
||||
|
||||
static const char * const ALLOWED_FW_11[] __initconst = {
|
||||
"16S6EMS1.111", // Prestige 15 a11scx
|
||||
"1552EMS1.115", // Modern 15 a11m
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct msi_ec_conf CONF11 __initdata = {
|
||||
.allowed_fw = ALLOWED_FW_11,
|
||||
.charge_control = {
|
||||
.address = 0xd7,
|
||||
.offset_start = 0x8a,
|
||||
.offset_end = 0x80,
|
||||
.range_min = 0x8a,
|
||||
.range_max = 0xe4,
|
||||
},
|
||||
.webcam = {
|
||||
.address = 0x2e,
|
||||
.block_address = MSI_EC_ADDR_UNKNOWN,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_win_swap = {
|
||||
.address = 0xe8,
|
||||
.bit = 4,
|
||||
},
|
||||
.cooler_boost = {
|
||||
.address = 0x98,
|
||||
.bit = 7,
|
||||
},
|
||||
.shift_mode = {
|
||||
.address = 0xd2,
|
||||
.modes = {
|
||||
{ SM_ECO_NAME, 0xc2 },
|
||||
{ SM_COMFORT_NAME, 0xc1 },
|
||||
{ SM_SPORT_NAME, 0xc0 },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.super_battery = {
|
||||
.address = 0xeb,
|
||||
.mask = 0x0f,
|
||||
},
|
||||
.fan_mode = {
|
||||
.address = 0xd4,
|
||||
.modes = {
|
||||
{ FM_AUTO_NAME, 0x0d },
|
||||
{ FM_SILENT_NAME, 0x1d },
|
||||
{ FM_ADVANCED_NAME, 0x4d },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.cpu = {
|
||||
.rt_temp_address = 0x68,
|
||||
.rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
|
||||
.bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
|
||||
},
|
||||
.gpu = {
|
||||
.rt_temp_address = MSI_EC_ADDR_UNSUPP,
|
||||
.rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
|
||||
},
|
||||
.leds = {
|
||||
.micmute_led_address = 0x2c,
|
||||
.mute_led_address = 0x2d,
|
||||
.bit = 1,
|
||||
},
|
||||
.kbd_bl = {
|
||||
.bl_mode_address = MSI_EC_ADDR_UNKNOWN,
|
||||
.bl_modes = {}, // ?
|
||||
.max_mode = 1, // ?
|
||||
.bl_state_address = 0xd3,
|
||||
.state_base_value = 0x80,
|
||||
.max_state = 3,
|
||||
},
|
||||
};
|
||||
|
||||
static const char * const ALLOWED_FW_12[] __initconst = {
|
||||
"16R6EMS1.104", // GF63 Thin 11UC
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct msi_ec_conf CONF12 __initdata = {
|
||||
.allowed_fw = ALLOWED_FW_12,
|
||||
.charge_control = {
|
||||
.address = 0xd7,
|
||||
.offset_start = 0x8a,
|
||||
.offset_end = 0x80,
|
||||
.range_min = 0x8a,
|
||||
.range_max = 0xe4,
|
||||
},
|
||||
.webcam = {
|
||||
.address = 0x2e,
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_win_swap = {
|
||||
.address = 0xe8,
|
||||
.bit = 4,
|
||||
},
|
||||
.cooler_boost = {
|
||||
.address = 0x98,
|
||||
.bit = 7,
|
||||
},
|
||||
.shift_mode = {
|
||||
.address = 0xd2,
|
||||
.modes = {
|
||||
{ SM_ECO_NAME, 0xc2 },
|
||||
{ SM_COMFORT_NAME, 0xc1 },
|
||||
{ SM_SPORT_NAME, 0xc0 },
|
||||
{ SM_TURBO_NAME, 0xc4 },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.super_battery = {
|
||||
.address = MSI_EC_ADDR_UNSUPP, // 0xeb
|
||||
.mask = 0x0f, // 00, 0f
|
||||
},
|
||||
.fan_mode = {
|
||||
.address = 0xd4,
|
||||
.modes = {
|
||||
{ FM_AUTO_NAME, 0x0d },
|
||||
{ FM_SILENT_NAME, 0x1d },
|
||||
{ FM_ADVANCED_NAME, 0x8d },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.cpu = {
|
||||
.rt_temp_address = 0x68,
|
||||
.rt_fan_speed_address = 0x71,
|
||||
.rt_fan_speed_base_min = 0x19,
|
||||
.rt_fan_speed_base_max = 0x37,
|
||||
.bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
|
||||
.bs_fan_speed_base_min = 0x00,
|
||||
.bs_fan_speed_base_max = 0x0f,
|
||||
},
|
||||
.gpu = {
|
||||
.rt_temp_address = MSI_EC_ADDR_UNSUPP,
|
||||
.rt_fan_speed_address = 0x89,
|
||||
},
|
||||
.leds = {
|
||||
.micmute_led_address = MSI_EC_ADDR_UNSUPP,
|
||||
.mute_led_address = 0x2d,
|
||||
.bit = 1,
|
||||
},
|
||||
.kbd_bl = {
|
||||
.bl_mode_address = MSI_EC_ADDR_UNKNOWN,
|
||||
.bl_modes = { 0x00, 0x08 },
|
||||
.max_mode = 1,
|
||||
.bl_state_address = 0xd3,
|
||||
.state_base_value = 0x80,
|
||||
.max_state = 3,
|
||||
},
|
||||
};
|
||||
|
||||
static const char * const ALLOWED_FW_13[] __initconst = {
|
||||
"1594EMS1.109", // MSI Prestige 16 Studio A13VE
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct msi_ec_conf CONF13 __initdata = {
|
||||
.allowed_fw = ALLOWED_FW_13,
|
||||
.charge_control = {
|
||||
.address = 0xd7,
|
||||
.offset_start = 0x8a,
|
||||
.offset_end = 0x80,
|
||||
.range_min = 0x8a,
|
||||
.range_max = 0xe4,
|
||||
},
|
||||
.webcam = {
|
||||
.address = 0x2e,
|
||||
.block_address = 0x2f,
|
||||
.bit = 1,
|
||||
},
|
||||
.fn_win_swap = {
|
||||
.address = 0xe8,
|
||||
.bit = 4, // 0x00-0x10
|
||||
},
|
||||
.cooler_boost = {
|
||||
.address = 0x98,
|
||||
.bit = 7,
|
||||
},
|
||||
.shift_mode = {
|
||||
.address = 0xd2,
|
||||
.modes = {
|
||||
{ SM_ECO_NAME, 0xc2 }, // super battery
|
||||
{ SM_COMFORT_NAME, 0xc1 }, // balanced
|
||||
{ SM_TURBO_NAME, 0xc4 }, // extreme
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.super_battery = {
|
||||
.address = MSI_EC_ADDR_UNSUPP,
|
||||
.mask = 0x0f, // 00, 0f
|
||||
},
|
||||
.fan_mode = {
|
||||
.address = 0xd4,
|
||||
.modes = {
|
||||
{ FM_AUTO_NAME, 0x0d },
|
||||
{ FM_SILENT_NAME, 0x1d },
|
||||
{ FM_ADVANCED_NAME, 0x8d },
|
||||
MSI_EC_MODE_NULL
|
||||
},
|
||||
},
|
||||
.cpu = {
|
||||
.rt_temp_address = 0x68,
|
||||
.rt_fan_speed_address = 0x71, // 0x0-0x96
|
||||
.rt_fan_speed_base_min = 0x00,
|
||||
.rt_fan_speed_base_max = 0x96,
|
||||
.bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
|
||||
.bs_fan_speed_base_min = 0x00,
|
||||
.bs_fan_speed_base_max = 0x0f,
|
||||
},
|
||||
.gpu = {
|
||||
.rt_temp_address = 0x80,
|
||||
.rt_fan_speed_address = 0x89,
|
||||
},
|
||||
.leds = {
|
||||
.micmute_led_address = 0x2c,
|
||||
.mute_led_address = 0x2d,
|
||||
.bit = 1,
|
||||
},
|
||||
.kbd_bl = {
|
||||
.bl_mode_address = 0x2c, // KB auto turn off
|
||||
.bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec
|
||||
.max_mode = 1,
|
||||
.bl_state_address = 0xd3,
|
||||
.state_base_value = 0x80,
|
||||
.max_state = 3,
|
||||
},
|
||||
};
|
||||
|
||||
static struct msi_ec_conf *CONFIGS[] __initdata = {
|
||||
&CONF0,
|
||||
&CONF1,
|
||||
@ -676,6 +1137,12 @@ static struct msi_ec_conf *CONFIGS[] __initdata = {
|
||||
&CONF5,
|
||||
&CONF6,
|
||||
&CONF7,
|
||||
&CONF8,
|
||||
&CONF9,
|
||||
&CONF10,
|
||||
&CONF11,
|
||||
&CONF12,
|
||||
&CONF13,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -40,7 +40,7 @@ struct msi_ec_webcam_conf {
|
||||
int bit;
|
||||
};
|
||||
|
||||
struct msi_ec_fn_super_swap_conf {
|
||||
struct msi_ec_fn_win_swap_conf {
|
||||
int address;
|
||||
int bit;
|
||||
};
|
||||
@ -108,7 +108,7 @@ struct msi_ec_conf {
|
||||
|
||||
struct msi_ec_charge_control_conf charge_control;
|
||||
struct msi_ec_webcam_conf webcam;
|
||||
struct msi_ec_fn_super_swap_conf fn_super_swap;
|
||||
struct msi_ec_fn_win_swap_conf fn_win_swap;
|
||||
struct msi_ec_cooler_boost_conf cooler_boost;
|
||||
struct msi_ec_shift_mode_conf shift_mode;
|
||||
struct msi_ec_super_battery_conf super_battery;
|
||||
|
@ -218,15 +218,13 @@ err_platform:
|
||||
return rs;
|
||||
}
|
||||
|
||||
static int sel3350_remove(struct platform_device *pdev)
|
||||
static void sel3350_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sel3350_data *sel3350 = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_unregister(sel3350->leds_pdev);
|
||||
gpiod_remove_lookup_table(&sel3350_gpios_table);
|
||||
gpiod_remove_lookup_table(&sel3350_leds_table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id sel3350_device_ids[] = {
|
||||
@ -237,7 +235,7 @@ MODULE_DEVICE_TABLE(acpi, sel3350_device_ids);
|
||||
|
||||
static struct platform_driver sel3350_platform_driver = {
|
||||
.probe = sel3350_probe,
|
||||
.remove = sel3350_remove,
|
||||
.remove_new = sel3350_remove,
|
||||
.driver = {
|
||||
.name = "sel3350-platform",
|
||||
.acpi_match_table = sel3350_device_ids,
|
||||
|
@ -25,9 +25,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_127e = {
|
||||
},
|
||||
};
|
||||
|
||||
static int simatic_ipc_batt_apollolake_remove(struct platform_device *pdev)
|
||||
static void simatic_ipc_batt_apollolake_remove(struct platform_device *pdev)
|
||||
{
|
||||
return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e);
|
||||
simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e);
|
||||
}
|
||||
|
||||
static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev)
|
||||
@ -37,7 +37,7 @@ static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver simatic_ipc_batt_driver = {
|
||||
.probe = simatic_ipc_batt_apollolake_probe,
|
||||
.remove = simatic_ipc_batt_apollolake_remove,
|
||||
.remove_new = simatic_ipc_batt_apollolake_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
},
|
||||
|
@ -25,9 +25,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_21a = {
|
||||
},
|
||||
};
|
||||
|
||||
static int simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev)
|
||||
static void simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev)
|
||||
{
|
||||
return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a);
|
||||
simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a);
|
||||
}
|
||||
|
||||
static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev)
|
||||
@ -37,7 +37,7 @@ static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver simatic_ipc_batt_driver = {
|
||||
.probe = simatic_ipc_batt_elkhartlake_probe,
|
||||
.remove = simatic_ipc_batt_elkhartlake_remove,
|
||||
.remove_new = simatic_ipc_batt_elkhartlake_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
},
|
||||
|
@ -45,9 +45,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_59a = {
|
||||
}
|
||||
};
|
||||
|
||||
static int simatic_ipc_batt_f7188x_remove(struct platform_device *pdev)
|
||||
static void simatic_ipc_batt_f7188x_remove(struct platform_device *pdev)
|
||||
{
|
||||
return simatic_ipc_batt_remove(pdev, batt_lookup_table);
|
||||
simatic_ipc_batt_remove(pdev, batt_lookup_table);
|
||||
}
|
||||
|
||||
static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev)
|
||||
@ -73,7 +73,7 @@ static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver simatic_ipc_batt_driver = {
|
||||
.probe = simatic_ipc_batt_f7188x_probe,
|
||||
.remove = simatic_ipc_batt_f7188x_remove,
|
||||
.remove_new = simatic_ipc_batt_f7188x_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
},
|
||||
|
@ -146,10 +146,9 @@ static const struct hwmon_chip_info simatic_ipc_batt_chip_info = {
|
||||
.info = simatic_ipc_batt_info,
|
||||
};
|
||||
|
||||
int simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table)
|
||||
void simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table)
|
||||
{
|
||||
gpiod_remove_lookup_table(table);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(simatic_ipc_batt_remove);
|
||||
|
||||
@ -228,9 +227,9 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(simatic_ipc_batt_probe);
|
||||
|
||||
static int simatic_ipc_batt_io_remove(struct platform_device *pdev)
|
||||
static void simatic_ipc_batt_io_remove(struct platform_device *pdev)
|
||||
{
|
||||
return simatic_ipc_batt_remove(pdev, NULL);
|
||||
simatic_ipc_batt_remove(pdev, NULL);
|
||||
}
|
||||
|
||||
static int simatic_ipc_batt_io_probe(struct platform_device *pdev)
|
||||
@ -240,7 +239,7 @@ static int simatic_ipc_batt_io_probe(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver simatic_ipc_batt_driver = {
|
||||
.probe = simatic_ipc_batt_io_probe,
|
||||
.remove = simatic_ipc_batt_io_remove,
|
||||
.remove_new = simatic_ipc_batt_io_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
},
|
||||
|
@ -14,7 +14,7 @@
|
||||
int simatic_ipc_batt_probe(struct platform_device *pdev,
|
||||
struct gpiod_lookup_table *table);
|
||||
|
||||
int simatic_ipc_batt_remove(struct platform_device *pdev,
|
||||
struct gpiod_lookup_table *table);
|
||||
void simatic_ipc_batt_remove(struct platform_device *pdev,
|
||||
struct gpiod_lookup_table *table);
|
||||
|
||||
#endif /* _SIMATIC_IPC_BATT_H */
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/wmi.h>
|
||||
@ -198,14 +198,6 @@ static struct think_lmi tlmi_priv;
|
||||
static struct class *fw_attr_class;
|
||||
static DEFINE_MUTEX(tlmi_mutex);
|
||||
|
||||
/* ------ Utility functions ------------*/
|
||||
/* Strip out CR if one is present */
|
||||
static void strip_cr(char *str)
|
||||
{
|
||||
char *p = strchrnul(str, '\n');
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
/* Convert BIOS WMI error string to suitable error code */
|
||||
static int tlmi_errstr_to_err(const char *errstr)
|
||||
{
|
||||
@ -411,7 +403,7 @@ static ssize_t current_password_store(struct kobject *kobj,
|
||||
|
||||
strscpy(setting->password, buf, setting->maxlen);
|
||||
/* Strip out CR if one is present, setting password won't work if it is present */
|
||||
strip_cr(setting->password);
|
||||
strreplace(setting->password, '\n', '\0');
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -432,13 +424,11 @@ static ssize_t new_password_store(struct kobject *kobj,
|
||||
if (!tlmi_priv.can_set_bios_password)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
new_pwd = kstrdup(buf, GFP_KERNEL);
|
||||
/* Strip out CR if one is present, setting password won't work if it is present */
|
||||
new_pwd = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
|
||||
if (!new_pwd)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Strip out CR if one is present, setting password won't work if it is present */
|
||||
strip_cr(new_pwd);
|
||||
|
||||
/* Use lock in case multiple WMI operations needed */
|
||||
mutex_lock(&tlmi_mutex);
|
||||
|
||||
@ -709,13 +699,11 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
|
||||
if (!setting->signature || !setting->signature[0])
|
||||
return -EACCES;
|
||||
|
||||
passwd = kstrdup(buf, GFP_KERNEL);
|
||||
/* Strip out CR if one is present */
|
||||
passwd = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
|
||||
if (!passwd)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Strip out CR if one is present */
|
||||
strip_cr(passwd);
|
||||
|
||||
/* Format: 'Password,Signature' */
|
||||
auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
|
||||
if (!auth_str) {
|
||||
@ -765,11 +753,10 @@ static ssize_t certificate_store(struct kobject *kobj,
|
||||
return ret ?: count;
|
||||
}
|
||||
|
||||
new_cert = kstrdup(buf, GFP_KERNEL);
|
||||
/* Strip out CR if one is present */
|
||||
new_cert = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
|
||||
if (!new_cert)
|
||||
return -ENOMEM;
|
||||
/* Strip out CR if one is present */
|
||||
strip_cr(new_cert);
|
||||
|
||||
if (setting->cert_installed) {
|
||||
/* Certificate is installed so this is an update */
|
||||
@ -817,13 +804,11 @@ static ssize_t signature_store(struct kobject *kobj,
|
||||
if (!tlmi_priv.certificate_support)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
new_signature = kstrdup(buf, GFP_KERNEL);
|
||||
/* Strip out CR if one is present */
|
||||
new_signature = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
|
||||
if (!new_signature)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Strip out CR if one is present */
|
||||
strip_cr(new_signature);
|
||||
|
||||
/* Free any previous signature */
|
||||
kfree(setting->signature);
|
||||
setting->signature = new_signature;
|
||||
@ -846,13 +831,11 @@ static ssize_t save_signature_store(struct kobject *kobj,
|
||||
if (!tlmi_priv.certificate_support)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
new_signature = kstrdup(buf, GFP_KERNEL);
|
||||
/* Strip out CR if one is present */
|
||||
new_signature = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
|
||||
if (!new_signature)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Strip out CR if one is present */
|
||||
strip_cr(new_signature);
|
||||
|
||||
/* Free any previous signature */
|
||||
kfree(setting->save_signature);
|
||||
setting->save_signature = new_signature;
|
||||
@ -930,7 +913,7 @@ static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *at
|
||||
static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
|
||||
char *item, *value, *p;
|
||||
char *item, *value;
|
||||
int ret;
|
||||
|
||||
ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID);
|
||||
@ -943,8 +926,7 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a
|
||||
ret = -EINVAL;
|
||||
else {
|
||||
/* On Workstations remove the Options part after the value */
|
||||
p = strchrnul(value, ';');
|
||||
*p = '\0';
|
||||
strreplace(value, ';', '\0');
|
||||
ret = sysfs_emit(buf, "%s\n", value + 1);
|
||||
}
|
||||
kfree(item);
|
||||
@ -985,12 +967,17 @@ static ssize_t current_value_store(struct kobject *kobj,
|
||||
if (!tlmi_priv.can_set_bios_settings)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
new_setting = kstrdup(buf, GFP_KERNEL);
|
||||
if (!new_setting)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* If we are using bulk saves a reboot should be done once save has
|
||||
* been called
|
||||
*/
|
||||
if (tlmi_priv.save_mode == TLMI_SAVE_BULK && tlmi_priv.reboot_required)
|
||||
return -EPERM;
|
||||
|
||||
/* Strip out CR if one is present */
|
||||
strip_cr(new_setting);
|
||||
new_setting = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
|
||||
if (!new_setting)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Use lock in case multiple WMI operations needed */
|
||||
mutex_lock(&tlmi_mutex);
|
||||
@ -1011,10 +998,11 @@ static ssize_t current_value_store(struct kobject *kobj,
|
||||
ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTING_CERT_GUID, set_str);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID,
|
||||
tlmi_priv.pwd_admin->save_signature);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (tlmi_priv.save_mode == TLMI_SAVE_BULK)
|
||||
tlmi_priv.save_required = true;
|
||||
else
|
||||
ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID,
|
||||
tlmi_priv.pwd_admin->save_signature);
|
||||
} else if (tlmi_priv.opcode_support) {
|
||||
/*
|
||||
* If opcode support is present use that interface.
|
||||
@ -1033,14 +1021,17 @@ static ssize_t current_value_store(struct kobject *kobj,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
|
||||
ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
|
||||
tlmi_priv.pwd_admin->password);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (tlmi_priv.save_mode == TLMI_SAVE_BULK) {
|
||||
tlmi_priv.save_required = true;
|
||||
} else {
|
||||
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
|
||||
ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
|
||||
tlmi_priv.pwd_admin->password);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
ret = tlmi_save_bios_settings("");
|
||||
}
|
||||
|
||||
ret = tlmi_save_bios_settings("");
|
||||
} else { /* old non-opcode based authentication method (deprecated) */
|
||||
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
|
||||
auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
|
||||
@ -1068,10 +1059,14 @@ static ssize_t current_value_store(struct kobject *kobj,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (auth_str)
|
||||
ret = tlmi_save_bios_settings(auth_str);
|
||||
else
|
||||
ret = tlmi_save_bios_settings("");
|
||||
if (tlmi_priv.save_mode == TLMI_SAVE_BULK) {
|
||||
tlmi_priv.save_required = true;
|
||||
} else {
|
||||
if (auth_str)
|
||||
ret = tlmi_save_bios_settings(auth_str);
|
||||
else
|
||||
ret = tlmi_save_bios_settings("");
|
||||
}
|
||||
}
|
||||
if (!ret && !tlmi_priv.pending_changes) {
|
||||
tlmi_priv.pending_changes = true;
|
||||
@ -1152,6 +1147,107 @@ static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *
|
||||
|
||||
static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
|
||||
|
||||
static const char * const save_mode_strings[] = {
|
||||
[TLMI_SAVE_SINGLE] = "single",
|
||||
[TLMI_SAVE_BULK] = "bulk",
|
||||
[TLMI_SAVE_SAVE] = "save"
|
||||
};
|
||||
|
||||
static ssize_t save_settings_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
/* Check that setting is valid */
|
||||
if (WARN_ON(tlmi_priv.save_mode < TLMI_SAVE_SINGLE ||
|
||||
tlmi_priv.save_mode > TLMI_SAVE_BULK))
|
||||
return -EIO;
|
||||
return sysfs_emit(buf, "%s\n", save_mode_strings[tlmi_priv.save_mode]);
|
||||
}
|
||||
|
||||
static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
char *auth_str = NULL;
|
||||
int ret = 0;
|
||||
int cmd;
|
||||
|
||||
cmd = sysfs_match_string(save_mode_strings, buf);
|
||||
if (cmd < 0)
|
||||
return cmd;
|
||||
|
||||
/* Use lock in case multiple WMI operations needed */
|
||||
mutex_lock(&tlmi_mutex);
|
||||
|
||||
switch (cmd) {
|
||||
case TLMI_SAVE_SINGLE:
|
||||
case TLMI_SAVE_BULK:
|
||||
tlmi_priv.save_mode = cmd;
|
||||
goto out;
|
||||
case TLMI_SAVE_SAVE:
|
||||
/* Check if supported*/
|
||||
if (!tlmi_priv.can_set_bios_settings ||
|
||||
tlmi_priv.save_mode == TLMI_SAVE_SINGLE) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
/* Check there is actually something to save */
|
||||
if (!tlmi_priv.save_required) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
/* Check if certificate authentication is enabled and active */
|
||||
if (tlmi_priv.certificate_support && tlmi_priv.pwd_admin->cert_installed) {
|
||||
if (!tlmi_priv.pwd_admin->signature ||
|
||||
!tlmi_priv.pwd_admin->save_signature) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID,
|
||||
tlmi_priv.pwd_admin->save_signature);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else if (tlmi_priv.opcode_support) {
|
||||
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
|
||||
ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
|
||||
tlmi_priv.pwd_admin->password);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
ret = tlmi_save_bios_settings("");
|
||||
} else { /* old non-opcode based authentication method (deprecated) */
|
||||
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
|
||||
auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
|
||||
tlmi_priv.pwd_admin->password,
|
||||
encoding_options[tlmi_priv.pwd_admin->encoding],
|
||||
tlmi_priv.pwd_admin->kbdlang);
|
||||
if (!auth_str) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (auth_str)
|
||||
ret = tlmi_save_bios_settings(auth_str);
|
||||
else
|
||||
ret = tlmi_save_bios_settings("");
|
||||
}
|
||||
tlmi_priv.save_required = false;
|
||||
tlmi_priv.reboot_required = true;
|
||||
|
||||
if (!ret && !tlmi_priv.pending_changes) {
|
||||
tlmi_priv.pending_changes = true;
|
||||
/* let userland know it may need to check reboot pending again */
|
||||
kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&tlmi_mutex);
|
||||
kfree(auth_str);
|
||||
return ret ?: count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute save_settings = __ATTR_RW(save_settings);
|
||||
|
||||
/* ---- Debug interface--------------------------------------------------------- */
|
||||
static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@ -1163,13 +1259,11 @@ static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr
|
||||
if (!tlmi_priv.can_debug_cmd)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
new_setting = kstrdup(buf, GFP_KERNEL);
|
||||
/* Strip out CR if one is present */
|
||||
new_setting = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL);
|
||||
if (!new_setting)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Strip out CR if one is present */
|
||||
strip_cr(new_setting);
|
||||
|
||||
if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
|
||||
auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
|
||||
tlmi_priv.pwd_admin->password,
|
||||
@ -1221,6 +1315,8 @@ static void tlmi_release_attr(void)
|
||||
}
|
||||
}
|
||||
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr);
|
||||
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &save_settings.attr);
|
||||
|
||||
if (tlmi_priv.can_debug_cmd && debug_support)
|
||||
sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
|
||||
|
||||
@ -1318,6 +1414,10 @@ static int tlmi_sysfs_init(void)
|
||||
if (ret)
|
||||
goto fail_create_attr;
|
||||
|
||||
ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &save_settings.attr);
|
||||
if (ret)
|
||||
goto fail_create_attr;
|
||||
|
||||
if (tlmi_priv.can_debug_cmd && debug_support) {
|
||||
ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr);
|
||||
if (ret)
|
||||
@ -1447,7 +1547,6 @@ static int tlmi_analyze(void)
|
||||
for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
|
||||
struct tlmi_attr_setting *setting;
|
||||
char *item = NULL;
|
||||
char *p;
|
||||
|
||||
tlmi_priv.setting[i] = NULL;
|
||||
ret = tlmi_setting(i, &item, LENOVO_BIOS_SETTING_GUID);
|
||||
@ -1464,8 +1563,7 @@ static int tlmi_analyze(void)
|
||||
strreplace(item, '/', '\\');
|
||||
|
||||
/* Remove the value part */
|
||||
p = strchrnul(item, ',');
|
||||
*p = '\0';
|
||||
strreplace(item, ',', '\0');
|
||||
|
||||
/* Create a setting entry */
|
||||
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
|
||||
|
@ -27,6 +27,19 @@ enum level_option {
|
||||
TLMI_LEVEL_MASTER,
|
||||
};
|
||||
|
||||
/*
|
||||
* There are a limit on the number of WMI operations you can do if you use
|
||||
* the default implementation of saving on every set. This is due to a
|
||||
* limitation in EFI variable space used.
|
||||
* Have a 'bulk save' mode where you can manually trigger the save, and can
|
||||
* therefore set unlimited variables - for users that need it.
|
||||
*/
|
||||
enum save_mode {
|
||||
TLMI_SAVE_SINGLE,
|
||||
TLMI_SAVE_BULK,
|
||||
TLMI_SAVE_SAVE,
|
||||
};
|
||||
|
||||
/* password configuration details */
|
||||
struct tlmi_pwdcfg_core {
|
||||
uint32_t password_mode;
|
||||
@ -86,6 +99,9 @@ struct think_lmi {
|
||||
bool can_debug_cmd;
|
||||
bool opcode_support;
|
||||
bool certificate_support;
|
||||
enum save_mode save_mode;
|
||||
bool save_required;
|
||||
bool reboot_required;
|
||||
|
||||
struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT];
|
||||
struct device *class_dev;
|
||||
|
@ -9816,6 +9816,7 @@ static const struct tpacpi_quirk battery_quirk_table[] __initconst = {
|
||||
* Individual addressing is broken on models that expose the
|
||||
* primary battery as BAT1.
|
||||
*/
|
||||
TPACPI_Q_LNV('8', 'F', true), /* Thinkpad X120e */
|
||||
TPACPI_Q_LNV('J', '7', true), /* B5400 */
|
||||
TPACPI_Q_LNV('J', 'I', true), /* Thinkpad 11e */
|
||||
TPACPI_Q_LNV3('R', '0', 'B', true), /* Thinkpad 11e gen 3 */
|
||||
@ -10787,6 +10788,89 @@ static struct ibm_struct dprc_driver_data = {
|
||||
.name = "dprc",
|
||||
};
|
||||
|
||||
/*
|
||||
* Auxmac
|
||||
*
|
||||
* This auxiliary mac address is enabled in the bios through the
|
||||
* MAC Address Pass-through feature. In most cases, there are three
|
||||
* possibilities: Internal Mac, Second Mac, and disabled.
|
||||
*
|
||||
*/
|
||||
|
||||
#define AUXMAC_LEN 12
|
||||
#define AUXMAC_START 9
|
||||
#define AUXMAC_STRLEN 22
|
||||
#define AUXMAC_BEGIN_MARKER 8
|
||||
#define AUXMAC_END_MARKER 21
|
||||
|
||||
static char auxmac[AUXMAC_LEN + 1];
|
||||
|
||||
static int auxmac_init(struct ibm_init_struct *iibm)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
|
||||
status = acpi_evaluate_object(NULL, "\\MACA", NULL, &buffer);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
obj = buffer.pointer;
|
||||
|
||||
if (obj->type != ACPI_TYPE_STRING || obj->string.length != AUXMAC_STRLEN) {
|
||||
pr_info("Invalid buffer for MAC address pass-through.\n");
|
||||
goto auxmacinvalid;
|
||||
}
|
||||
|
||||
if (obj->string.pointer[AUXMAC_BEGIN_MARKER] != '#' ||
|
||||
obj->string.pointer[AUXMAC_END_MARKER] != '#') {
|
||||
pr_info("Invalid header for MAC address pass-through.\n");
|
||||
goto auxmacinvalid;
|
||||
}
|
||||
|
||||
if (strncmp(obj->string.pointer + AUXMAC_START, "XXXXXXXXXXXX", AUXMAC_LEN) != 0)
|
||||
strscpy(auxmac, obj->string.pointer + AUXMAC_START, sizeof(auxmac));
|
||||
else
|
||||
strscpy(auxmac, "disabled", sizeof(auxmac));
|
||||
|
||||
free:
|
||||
kfree(obj);
|
||||
return 0;
|
||||
|
||||
auxmacinvalid:
|
||||
strscpy(auxmac, "unavailable", sizeof(auxmac));
|
||||
goto free;
|
||||
}
|
||||
|
||||
static struct ibm_struct auxmac_data = {
|
||||
.name = "auxmac",
|
||||
};
|
||||
|
||||
static ssize_t auxmac_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%s\n", auxmac);
|
||||
}
|
||||
static DEVICE_ATTR_RO(auxmac);
|
||||
|
||||
static umode_t auxmac_attr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
return auxmac[0] == 0 ? 0 : attr->mode;
|
||||
}
|
||||
|
||||
static struct attribute *auxmac_attributes[] = {
|
||||
&dev_attr_auxmac.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group auxmac_attr_group = {
|
||||
.is_visible = auxmac_attr_is_visible,
|
||||
.attrs = auxmac_attributes,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static struct attribute *tpacpi_driver_attributes[] = {
|
||||
@ -10845,6 +10929,7 @@ static const struct attribute_group *tpacpi_groups[] = {
|
||||
&proxsensor_attr_group,
|
||||
&kbdlang_attr_group,
|
||||
&dprc_attr_group,
|
||||
&auxmac_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -11144,6 +11229,8 @@ invalid:
|
||||
return '\0';
|
||||
}
|
||||
|
||||
#define EC_FW_STRING_LEN 18
|
||||
|
||||
static void find_new_ec_fwstr(const struct dmi_header *dm, void *private)
|
||||
{
|
||||
char *ec_fw_string = (char *) private;
|
||||
@ -11172,7 +11259,8 @@ static void find_new_ec_fwstr(const struct dmi_header *dm, void *private)
|
||||
return;
|
||||
|
||||
/* fwstr is the first 8byte string */
|
||||
strncpy(ec_fw_string, dmi_data + 0x0F, 8);
|
||||
BUILD_BUG_ON(EC_FW_STRING_LEN <= 8);
|
||||
memcpy(ec_fw_string, dmi_data + 0x0F, 8);
|
||||
}
|
||||
|
||||
/* returns 0 - probe ok, or < 0 - probe error.
|
||||
@ -11182,7 +11270,7 @@ static int __must_check __init get_thinkpad_model_data(
|
||||
struct thinkpad_id_data *tp)
|
||||
{
|
||||
const struct dmi_device *dev = NULL;
|
||||
char ec_fw_string[18] = {0};
|
||||
char ec_fw_string[EC_FW_STRING_LEN] = {0};
|
||||
char const *s;
|
||||
char t;
|
||||
|
||||
@ -11416,6 +11504,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
|
||||
.init = tpacpi_dprc_init,
|
||||
.data = &dprc_driver_data,
|
||||
},
|
||||
{
|
||||
.init = auxmac_init,
|
||||
.data = &auxmac_data,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
|
||||
|
@ -109,33 +109,13 @@ static const char * const allow_duplicates[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
|
||||
#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
|
||||
|
||||
/*
|
||||
* GUID parsing functions
|
||||
*/
|
||||
|
||||
static acpi_status find_guid(const char *guid_string, struct wmi_block **out)
|
||||
{
|
||||
guid_t guid_input;
|
||||
struct wmi_block *wblock;
|
||||
|
||||
if (!guid_string)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
if (guid_parse(guid_string, &guid_input))
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
list_for_each_entry(wblock, &wmi_block_list, list) {
|
||||
if (guid_equal(&wblock->gblock.guid, &guid_input)) {
|
||||
if (out)
|
||||
*out = wblock;
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return AE_NOT_FOUND;
|
||||
}
|
||||
|
||||
static bool guid_parse_and_compare(const char *string, const guid_t *guid)
|
||||
{
|
||||
guid_t guid_input;
|
||||
@ -245,6 +225,41 @@ static acpi_status get_event_data(const struct wmi_block *wblock, struct acpi_bu
|
||||
return acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, out);
|
||||
}
|
||||
|
||||
static int wmidev_match_guid(struct device *dev, const void *data)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
const guid_t *guid = data;
|
||||
|
||||
if (guid_equal(guid, &wblock->gblock.guid))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bus_type wmi_bus_type;
|
||||
|
||||
static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
|
||||
{
|
||||
struct device *dev;
|
||||
guid_t guid;
|
||||
int ret;
|
||||
|
||||
ret = guid_parse(guid_string, &guid);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
dev = bus_find_device(&wmi_bus_type, NULL, &guid, wmidev_match_guid);
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return dev_to_wdev(dev);
|
||||
}
|
||||
|
||||
static void wmi_device_put(struct wmi_device *wdev)
|
||||
{
|
||||
put_device(&wdev->dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported WMI functions
|
||||
*/
|
||||
@ -279,18 +294,17 @@ EXPORT_SYMBOL_GPL(set_required_buffer_size);
|
||||
*/
|
||||
int wmi_instance_count(const char *guid_string)
|
||||
{
|
||||
struct wmi_block *wblock;
|
||||
acpi_status status;
|
||||
struct wmi_device *wdev;
|
||||
int ret;
|
||||
|
||||
status = find_guid(guid_string, &wblock);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (status == AE_BAD_PARAMETER)
|
||||
return -EINVAL;
|
||||
wdev = wmi_find_device_by_guid(guid_string);
|
||||
if (IS_ERR(wdev))
|
||||
return PTR_ERR(wdev);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = wmidev_instance_count(wdev);
|
||||
wmi_device_put(wdev);
|
||||
|
||||
return wmidev_instance_count(&wblock->dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_instance_count);
|
||||
|
||||
@ -325,15 +339,18 @@ EXPORT_SYMBOL_GPL(wmidev_instance_count);
|
||||
acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, u32 method_id,
|
||||
const struct acpi_buffer *in, struct acpi_buffer *out)
|
||||
{
|
||||
struct wmi_block *wblock = NULL;
|
||||
struct wmi_device *wdev;
|
||||
acpi_status status;
|
||||
|
||||
status = find_guid(guid_string, &wblock);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
wdev = wmi_find_device_by_guid(guid_string);
|
||||
if (IS_ERR(wdev))
|
||||
return AE_ERROR;
|
||||
|
||||
return wmidev_evaluate_method(&wblock->dev, instance, method_id,
|
||||
in, out);
|
||||
status = wmidev_evaluate_method(wdev, instance, method_id, in, out);
|
||||
|
||||
wmi_device_put(wdev);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_evaluate_method);
|
||||
|
||||
@ -472,13 +489,19 @@ acpi_status wmi_query_block(const char *guid_string, u8 instance,
|
||||
struct acpi_buffer *out)
|
||||
{
|
||||
struct wmi_block *wblock;
|
||||
struct wmi_device *wdev;
|
||||
acpi_status status;
|
||||
|
||||
status = find_guid(guid_string, &wblock);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
wdev = wmi_find_device_by_guid(guid_string);
|
||||
if (IS_ERR(wdev))
|
||||
return AE_ERROR;
|
||||
|
||||
return __query_block(wblock, instance, out);
|
||||
wblock = container_of(wdev, struct wmi_block, dev);
|
||||
status = __query_block(wblock, instance, out);
|
||||
|
||||
wmi_device_put(wdev);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_query_block);
|
||||
|
||||
@ -516,8 +539,9 @@ EXPORT_SYMBOL_GPL(wmidev_block_query);
|
||||
acpi_status wmi_set_block(const char *guid_string, u8 instance,
|
||||
const struct acpi_buffer *in)
|
||||
{
|
||||
struct wmi_block *wblock = NULL;
|
||||
struct wmi_block *wblock;
|
||||
struct guid_block *block;
|
||||
struct wmi_device *wdev;
|
||||
acpi_handle handle;
|
||||
struct acpi_object_list input;
|
||||
union acpi_object params[2];
|
||||
@ -527,19 +551,26 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance,
|
||||
if (!in)
|
||||
return AE_BAD_DATA;
|
||||
|
||||
status = find_guid(guid_string, &wblock);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
wdev = wmi_find_device_by_guid(guid_string);
|
||||
if (IS_ERR(wdev))
|
||||
return AE_ERROR;
|
||||
|
||||
wblock = container_of(wdev, struct wmi_block, dev);
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->acpi_device->handle;
|
||||
|
||||
if (block->instance_count <= instance)
|
||||
return AE_BAD_PARAMETER;
|
||||
if (block->instance_count <= instance) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
|
||||
goto err_wdev_put;
|
||||
}
|
||||
|
||||
/* Check GUID is a data block */
|
||||
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
|
||||
return AE_ERROR;
|
||||
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) {
|
||||
status = AE_ERROR;
|
||||
|
||||
goto err_wdev_put;
|
||||
}
|
||||
|
||||
input.count = 2;
|
||||
input.pointer = params;
|
||||
@ -551,7 +582,12 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance,
|
||||
|
||||
get_acpi_method_name(wblock, 'S', method);
|
||||
|
||||
return acpi_evaluate_object(handle, method, &input, NULL);
|
||||
status = acpi_evaluate_object(handle, method, &input, NULL);
|
||||
|
||||
err_wdev_put:
|
||||
wmi_device_put(wdev);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_set_block);
|
||||
|
||||
@ -742,7 +778,15 @@ EXPORT_SYMBOL_GPL(wmi_get_event_data);
|
||||
*/
|
||||
bool wmi_has_guid(const char *guid_string)
|
||||
{
|
||||
return ACPI_SUCCESS(find_guid(guid_string, NULL));
|
||||
struct wmi_device *wdev;
|
||||
|
||||
wdev = wmi_find_device_by_guid(guid_string);
|
||||
if (IS_ERR(wdev))
|
||||
return false;
|
||||
|
||||
wmi_device_put(wdev);
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_has_guid);
|
||||
|
||||
@ -756,20 +800,23 @@ EXPORT_SYMBOL_GPL(wmi_has_guid);
|
||||
*/
|
||||
char *wmi_get_acpi_device_uid(const char *guid_string)
|
||||
{
|
||||
struct wmi_block *wblock = NULL;
|
||||
acpi_status status;
|
||||
struct wmi_block *wblock;
|
||||
struct wmi_device *wdev;
|
||||
char *uid;
|
||||
|
||||
status = find_guid(guid_string, &wblock);
|
||||
if (ACPI_FAILURE(status))
|
||||
wdev = wmi_find_device_by_guid(guid_string);
|
||||
if (IS_ERR(wdev))
|
||||
return NULL;
|
||||
|
||||
return acpi_device_uid(wblock->acpi_device);
|
||||
wblock = container_of(wdev, struct wmi_block, dev);
|
||||
uid = acpi_device_uid(wblock->acpi_device);
|
||||
|
||||
wmi_device_put(wdev);
|
||||
|
||||
return uid;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);
|
||||
|
||||
#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
|
||||
#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
|
||||
|
||||
static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv)
|
||||
{
|
||||
return container_of(drv, struct wmi_driver, driver);
|
||||
@ -911,21 +958,13 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver)
|
||||
}
|
||||
static int wmi_char_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
const char *driver_name = filp->f_path.dentry->d_iname;
|
||||
struct wmi_block *wblock;
|
||||
struct wmi_block *next;
|
||||
/*
|
||||
* The miscdevice already stores a pointer to itself
|
||||
* inside filp->private_data
|
||||
*/
|
||||
struct wmi_block *wblock = container_of(filp->private_data, struct wmi_block, char_dev);
|
||||
|
||||
list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
|
||||
if (!wblock->dev.dev.driver)
|
||||
continue;
|
||||
if (strcmp(driver_name, wblock->dev.dev.driver->name) == 0) {
|
||||
filp->private_data = wblock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!filp->private_data)
|
||||
return -ENODEV;
|
||||
filp->private_data = wblock;
|
||||
|
||||
return nonseekable_open(inode, filp);
|
||||
}
|
||||
@ -1221,17 +1260,24 @@ static int wmi_create_device(struct device *wmi_bus_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wmi_free_devices(struct acpi_device *device)
|
||||
static int wmi_add_device(struct platform_device *pdev, struct wmi_device *wdev)
|
||||
{
|
||||
struct wmi_block *wblock, *next;
|
||||
struct device_link *link;
|
||||
|
||||
/* Delete devices for all the GUIDs */
|
||||
list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
|
||||
if (wblock->acpi_device == device) {
|
||||
list_del(&wblock->list);
|
||||
device_unregister(&wblock->dev.dev);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Many aggregate WMI drivers do not use -EPROBE_DEFER when they
|
||||
* are unable to find a WMI device during probe, instead they require
|
||||
* all WMI devices associated with an platform device to become available
|
||||
* at once. This device link thus prevents WMI drivers from probing until
|
||||
* the associated platform device has finished probing (and has registered
|
||||
* all discovered WMI devices).
|
||||
*/
|
||||
|
||||
link = device_link_add(&wdev->dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
return device_add(&wdev->dev);
|
||||
}
|
||||
|
||||
static bool guid_already_parsed_for_legacy(struct acpi_device *device, const guid_t *guid)
|
||||
@ -1263,15 +1309,16 @@ static bool guid_already_parsed_for_legacy(struct acpi_device *device, const gui
|
||||
/*
|
||||
* Parse the _WDG method for the GUID data blocks
|
||||
*/
|
||||
static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
|
||||
static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
const struct guid_block *gblock;
|
||||
struct wmi_block *wblock, *next;
|
||||
struct wmi_block *wblock;
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
int retval = 0;
|
||||
u32 i, total;
|
||||
int retval;
|
||||
|
||||
status = acpi_evaluate_object(device->handle, "_WDG", NULL, &out);
|
||||
if (ACPI_FAILURE(status))
|
||||
@ -1282,8 +1329,8 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
|
||||
return -ENXIO;
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
retval = -ENXIO;
|
||||
goto out_free_pointer;
|
||||
kfree(obj);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
gblock = (const struct guid_block *)obj->buffer.pointer;
|
||||
@ -1298,8 +1345,8 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
|
||||
|
||||
wblock = kzalloc(sizeof(*wblock), GFP_KERNEL);
|
||||
if (!wblock) {
|
||||
retval = -ENOMEM;
|
||||
break;
|
||||
dev_err(wmi_bus_dev, "Failed to allocate %pUL\n", &gblock[i].guid);
|
||||
continue;
|
||||
}
|
||||
|
||||
wblock->acpi_device = device;
|
||||
@ -1317,30 +1364,22 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
|
||||
wblock->handler = wmi_notify_debug;
|
||||
wmi_method_enable(wblock, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that all of the devices are created, add them to the
|
||||
* device tree and probe subdrivers.
|
||||
*/
|
||||
list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
|
||||
if (wblock->acpi_device != device)
|
||||
continue;
|
||||
|
||||
retval = device_add(&wblock->dev.dev);
|
||||
retval = wmi_add_device(pdev, &wblock->dev);
|
||||
if (retval) {
|
||||
dev_err(wmi_bus_dev, "failed to register %pUL\n",
|
||||
&wblock->gblock.guid);
|
||||
if (debug_event)
|
||||
wmi_method_enable(wblock, false);
|
||||
|
||||
list_del(&wblock->list);
|
||||
put_device(&wblock->dev.dev);
|
||||
}
|
||||
}
|
||||
|
||||
out_free_pointer:
|
||||
kfree(out.pointer);
|
||||
return retval;
|
||||
kfree(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1435,16 +1474,28 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
|
||||
event, 0);
|
||||
}
|
||||
|
||||
static int wmi_remove_device(struct device *dev, void *data)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
||||
list_del(&wblock->list);
|
||||
device_unregister(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_wmi_remove(struct platform_device *device)
|
||||
{
|
||||
struct acpi_device *acpi_device = ACPI_COMPANION(&device->dev);
|
||||
struct device *wmi_bus_device = dev_get_drvdata(&device->dev);
|
||||
|
||||
acpi_remove_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY,
|
||||
acpi_wmi_notify_handler);
|
||||
acpi_remove_address_space_handler(acpi_device->handle,
|
||||
ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
|
||||
wmi_free_devices(acpi_device);
|
||||
device_unregister(dev_get_drvdata(&device->dev));
|
||||
|
||||
device_for_each_child_reverse(wmi_bus_device, NULL, wmi_remove_device);
|
||||
device_unregister(wmi_bus_device);
|
||||
}
|
||||
|
||||
static int acpi_wmi_probe(struct platform_device *device)
|
||||
@ -1487,7 +1538,7 @@ static int acpi_wmi_probe(struct platform_device *device)
|
||||
}
|
||||
dev_set_drvdata(&device->dev, wmi_bus_dev);
|
||||
|
||||
error = parse_wdg(wmi_bus_dev, acpi_device);
|
||||
error = parse_wdg(wmi_bus_dev, device);
|
||||
if (error) {
|
||||
pr_err("Failed to parse WDG method\n");
|
||||
goto err_remove_busdev;
|
||||
|
@ -24,6 +24,21 @@
|
||||
|
||||
static struct platform_device *x86_android_tablet_device;
|
||||
|
||||
/*
|
||||
* This helper allows getting a gpio_desc *before* the actual device consuming
|
||||
* the GPIO has been instantiated. This function _must_ only be used to handle
|
||||
* this special case such as e.g. :
|
||||
*
|
||||
* 1. Getting an IRQ from a GPIO for i2c_board_info.irq which is passed to
|
||||
* i2c_client_new() to instantiate i2c_client-s; or
|
||||
* 2. Calling desc_to_gpio() to get an old style GPIO number for gpio_keys
|
||||
* platform_data which still uses old style GPIO numbers.
|
||||
*
|
||||
* Since the consuming device has not been instatiated yet a dynamic lookup
|
||||
* is generated using the special x86_android_tablet dev for dev_id.
|
||||
*
|
||||
* For normal GPIO lookups a standard static gpiod_lookup_table _must_ be used.
|
||||
*/
|
||||
int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
|
||||
bool active_low, enum gpiod_flags dflags,
|
||||
struct gpio_desc **desc)
|
||||
|
@ -436,7 +436,7 @@ static int __init lenovo_yoga_tab2_830_1050_init_touchscreen(void)
|
||||
|
||||
/* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */
|
||||
ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, "yoga_bootstrap",
|
||||
false, GPIOD_IN, &gpiod);
|
||||
false, GPIOD_ASIS, &gpiod);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -81,9 +81,9 @@ static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
|
||||
|
||||
static int ebook_switch_add(struct acpi_device *device)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
struct ebook_switch *button;
|
||||
struct input_dev *input;
|
||||
const char *hid = acpi_device_hid(device);
|
||||
char *name, *class;
|
||||
int error;
|
||||
|
||||
@ -102,8 +102,9 @@ static int ebook_switch_add(struct acpi_device *device)
|
||||
name = acpi_device_name(device);
|
||||
class = acpi_device_class(device);
|
||||
|
||||
if (strcmp(hid, XO15_EBOOK_HID)) {
|
||||
pr_err("Unsupported hid [%s]\n", hid);
|
||||
id = acpi_match_acpi_device(ebook_device_ids, device);
|
||||
if (!id) {
|
||||
dev_err(&device->dev, "Unsupported hid\n");
|
||||
error = -ENODEV;
|
||||
goto err_free_input;
|
||||
}
|
||||
@ -111,7 +112,7 @@ static int ebook_switch_add(struct acpi_device *device)
|
||||
strcpy(name, XO15_EBOOK_DEVICE_NAME);
|
||||
sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS);
|
||||
|
||||
snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
|
||||
snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id);
|
||||
|
||||
input->name = name;
|
||||
input->phys = button->phys;
|
||||
|
@ -6,6 +6,12 @@
|
||||
#ifndef _INTEL_TPMI_H_
|
||||
#define _INTEL_TPMI_H_
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
#define TPMI_VERSION_INVALID 0xff
|
||||
#define TPMI_MINOR_VERSION(val) FIELD_GET(GENMASK(4, 0), val)
|
||||
#define TPMI_MAJOR_VERSION(val) FIELD_GET(GENMASK(7, 5), val)
|
||||
|
||||
/**
|
||||
* struct intel_tpmi_plat_info - Platform information for a TPMI device instance
|
||||
* @package_id: CPU Package id
|
||||
|
@ -58,6 +58,10 @@
|
||||
#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
|
||||
#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
|
||||
#define ASUS_WMI_DEVID_LIGHTBAR 0x00050025
|
||||
/* This can only be used to disable the screen, not re-enable */
|
||||
#define ASUS_WMI_DEVID_SCREENPAD_POWER 0x00050031
|
||||
/* Writing a brightness re-enables the screen if disabled */
|
||||
#define ASUS_WMI_DEVID_SCREENPAD_LIGHT 0x00050032
|
||||
#define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018
|
||||
#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
|
||||
|
||||
|
@ -44,7 +44,7 @@ struct ssam_event {
|
||||
u8 command_id;
|
||||
u8 instance_id;
|
||||
u16 length;
|
||||
u8 data[];
|
||||
u8 data[] __counted_by(length);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -10,25 +10,25 @@
|
||||
|
||||
TRACE_EVENT(ifs_status,
|
||||
|
||||
TP_PROTO(int cpu, union ifs_scan activate, union ifs_status status),
|
||||
TP_PROTO(int cpu, int start, int stop, u64 status),
|
||||
|
||||
TP_ARGS(cpu, activate, status),
|
||||
TP_ARGS(cpu, start, stop, status),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( u64, status )
|
||||
__field( int, cpu )
|
||||
__field( u8, start )
|
||||
__field( u8, stop )
|
||||
__field( u16, start )
|
||||
__field( u16, stop )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->cpu = cpu;
|
||||
__entry->start = activate.start;
|
||||
__entry->stop = activate.stop;
|
||||
__entry->status = status.data;
|
||||
__entry->start = start;
|
||||
__entry->stop = stop;
|
||||
__entry->status = status;
|
||||
),
|
||||
|
||||
TP_printk("cpu: %d, start: %.2x, stop: %.2x, status: %llx",
|
||||
TP_printk("cpu: %d, start: %.4x, stop: %.4x, status: %.16llx",
|
||||
__entry->cpu,
|
||||
__entry->start,
|
||||
__entry->stop,
|
||||
|
@ -4,8 +4,8 @@
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <linux/isst_if.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "isst.h"
|
||||
|
||||
@ -16,7 +16,7 @@ struct process_cmd_struct {
|
||||
int arg;
|
||||
};
|
||||
|
||||
static const char *version_str = "v1.17";
|
||||
static const char *version_str = "v1.18";
|
||||
|
||||
static const int supported_api_ver = 2;
|
||||
static struct isst_if_platform_info isst_platform_info;
|
||||
@ -27,7 +27,7 @@ static FILE *outf;
|
||||
static int cpu_model;
|
||||
static int cpu_stepping;
|
||||
|
||||
#define MAX_CPUS_IN_ONE_REQ 256
|
||||
#define MAX_CPUS_IN_ONE_REQ 512
|
||||
static short max_target_cpus;
|
||||
static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ];
|
||||
|
||||
@ -55,6 +55,8 @@ static int clos_min = -1;
|
||||
static int clos_max = -1;
|
||||
static int clos_desired = -1;
|
||||
static int clos_priority_type;
|
||||
static int cpu_0_cgroupv2;
|
||||
static int cpu_0_workaround(int isolate);
|
||||
|
||||
struct _cpu_map {
|
||||
unsigned short core_id;
|
||||
@ -474,42 +476,15 @@ static unsigned int is_cpu_online(int cpu)
|
||||
return online;
|
||||
}
|
||||
|
||||
static int get_kernel_version(int *major, int *minor)
|
||||
{
|
||||
struct utsname buf;
|
||||
int ret;
|
||||
|
||||
ret = uname(&buf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sscanf(buf.release, "%d.%d", major, minor);
|
||||
if (ret != 2)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CPU0_HOTPLUG_DEPRECATE_MAJOR_VER 6
|
||||
#define CPU0_HOTPLUG_DEPRECATE_MINOR_VER 5
|
||||
|
||||
void set_cpu_online_offline(int cpu, int state)
|
||||
{
|
||||
char buffer[128];
|
||||
int fd, ret;
|
||||
|
||||
if (!cpu) {
|
||||
int major, minor;
|
||||
|
||||
ret = get_kernel_version(&major, &minor);
|
||||
if (!ret) {
|
||||
if (major > CPU0_HOTPLUG_DEPRECATE_MAJOR_VER || (major == CPU0_HOTPLUG_DEPRECATE_MAJOR_VER &&
|
||||
minor >= CPU0_HOTPLUG_DEPRECATE_MINOR_VER)) {
|
||||
debug_printf("Ignore CPU 0 offline/online for kernel version >= %d.%d\n", major, minor);
|
||||
debug_printf("Use cgroups to isolate CPU 0\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cpu_0_cgroupv2 && !cpu) {
|
||||
fprintf(stderr, "Will use cgroup v2 for CPU 0\n");
|
||||
cpu_0_workaround(!state);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
@ -517,9 +492,10 @@ void set_cpu_online_offline(int cpu, int state)
|
||||
|
||||
fd = open(buffer, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
if (!cpu && state) {
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "This system is not configured for CPU 0 online/offline\n");
|
||||
fprintf(stderr, "Ignoring online request for CPU 0 as this is already online\n");
|
||||
fprintf(stderr, "Will use cgroup v2\n");
|
||||
cpu_0_workaround(!state);
|
||||
return;
|
||||
}
|
||||
err(-1, "%s open failed", buffer);
|
||||
@ -906,7 +882,7 @@ int enable_cpuset_controller(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level)
|
||||
int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level, int cpu_0_only)
|
||||
{
|
||||
int i, first, curr_index, index, ret, fd;
|
||||
static char str[512], dir_name[64];
|
||||
@ -949,6 +925,12 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev
|
||||
curr_index = 0;
|
||||
first = 1;
|
||||
str[0] = '\0';
|
||||
|
||||
if (cpu_0_only) {
|
||||
snprintf(str, str_len, "0");
|
||||
goto create_partition;
|
||||
}
|
||||
|
||||
for (i = 0; i < get_topo_max_cpus(); ++i) {
|
||||
if (!is_cpu_in_power_domain(i, id))
|
||||
continue;
|
||||
@ -971,6 +953,7 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev
|
||||
first = 0;
|
||||
}
|
||||
|
||||
create_partition:
|
||||
debug_printf("isolated CPUs list: package:%d curr_index:%d [%s]\n", id->pkg, curr_index ,str);
|
||||
|
||||
snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus", dir_name);
|
||||
@ -1011,6 +994,74 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpu_0_workaround(int isolate)
|
||||
{
|
||||
int fd, fd1, len, ret;
|
||||
cpu_set_t cpu_mask;
|
||||
struct isst_id id;
|
||||
char str[2];
|
||||
|
||||
debug_printf("isolate CPU 0 state: %d\n", isolate);
|
||||
|
||||
if (isolate)
|
||||
goto isolate;
|
||||
|
||||
/* First check if CPU 0 was isolated to remove isolation. */
|
||||
|
||||
/* If the cpuset.cpus doesn't exist, that means that none of the CPUs are isolated*/
|
||||
fd = open("/sys/fs/cgroup/0-0-0/cpuset.cpus", O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
len = read(fd, str, sizeof(str));
|
||||
/* Error check, but unlikely to fail. If fails that means that not isolated */
|
||||
if (len == -1)
|
||||
return 0;
|
||||
|
||||
|
||||
/* Is CPU 0 is in isolate list, the display is sorted so first element will be CPU 0*/
|
||||
if (str[0] != '0') {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd1 = open("/sys/fs/cgroup/0-0-0/cpuset.cpus.partition", O_RDONLY, 0);
|
||||
/* Unlikely that, this attribute is not present, but handle error */
|
||||
if (fd1 < 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is CPU 0 already changed partition to "member" */
|
||||
len = read(fd1, str, sizeof(str));
|
||||
if (len != -1 && str[0] == 'm') {
|
||||
close(fd1);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd1);
|
||||
close(fd);
|
||||
|
||||
debug_printf("CPU 0 was isolated before, so remove isolation\n");
|
||||
|
||||
isolate:
|
||||
ret = enable_cpuset_controller();
|
||||
if (ret)
|
||||
goto isolate_fail;
|
||||
|
||||
CPU_ZERO(&cpu_mask);
|
||||
memset(&id, 0, sizeof(struct isst_id));
|
||||
CPU_SET(0, &cpu_mask);
|
||||
|
||||
ret = isolate_cpus(&id, sizeof(cpu_mask), &cpu_mask, isolate, 1);
|
||||
isolate_fail:
|
||||
if (ret)
|
||||
fprintf(stderr, "Can't isolate CPU 0\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isst_fill_platform_info(void)
|
||||
{
|
||||
const char *pathname = "/dev/isst_interface";
|
||||
@ -1457,7 +1508,8 @@ display_result:
|
||||
if (ret)
|
||||
goto use_offline;
|
||||
|
||||
ret = isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, tdp_level);
|
||||
ret = isolate_cpus(id, ctdp_level.core_cpumask_size,
|
||||
ctdp_level.core_cpumask, tdp_level, 0);
|
||||
if (ret)
|
||||
goto use_offline;
|
||||
|
||||
@ -2125,7 +2177,7 @@ static void set_fact_enable(int arg)
|
||||
fprintf(stderr,
|
||||
"Enable Intel Speed Select Technology Turbo frequency feature\n");
|
||||
fprintf(stderr,
|
||||
"Optional: -t|--trl : Specify turbo ratio limit\n");
|
||||
"Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n");
|
||||
fprintf(stderr,
|
||||
"\tOptional Arguments: -a|--auto : Designate specified target CPUs with");
|
||||
fprintf(stderr,
|
||||
@ -2134,7 +2186,7 @@ static void set_fact_enable(int arg)
|
||||
fprintf(stderr,
|
||||
"Disable Intel Speed Select Technology turbo frequency feature\n");
|
||||
fprintf(stderr,
|
||||
"Optional: -t|--trl : Specify turbo ratio limit\n");
|
||||
"Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n");
|
||||
fprintf(stderr,
|
||||
"\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
|
||||
}
|
||||
@ -2241,6 +2293,14 @@ static void enable_clos_qos_config(struct isst_id *id, void *arg1, void *arg2, v
|
||||
{
|
||||
int ret;
|
||||
int status = *(int *)arg4;
|
||||
int cp_state, cp_cap;
|
||||
|
||||
if (!isst_read_pm_config(id, &cp_state, &cp_cap)) {
|
||||
if (!cp_cap) {
|
||||
isst_display_error_info_message(1, "core-power not supported", 0, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_skx_based_platform())
|
||||
clos_priority_type = 1;
|
||||
@ -2526,22 +2586,22 @@ static void set_turbo_mode_for_cpu(struct isst_id *id, int status)
|
||||
}
|
||||
|
||||
if (status) {
|
||||
isst_display_result(id, outf, "turbo-mode", "enable", 0);
|
||||
} else {
|
||||
isst_display_result(id, outf, "turbo-mode", "disable", 0);
|
||||
} else {
|
||||
isst_display_result(id, outf, "turbo-mode", "enable", 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_turbo_mode(int arg)
|
||||
{
|
||||
int i, enable = arg;
|
||||
int i, disable = arg;
|
||||
struct isst_id id;
|
||||
|
||||
if (cmd_help) {
|
||||
if (enable)
|
||||
fprintf(stderr, "Set turbo mode enable\n");
|
||||
else
|
||||
if (disable)
|
||||
fprintf(stderr, "Set turbo mode disable\n");
|
||||
else
|
||||
fprintf(stderr, "Set turbo mode enable\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -2559,7 +2619,7 @@ static void set_turbo_mode(int arg)
|
||||
|
||||
if (online) {
|
||||
set_isst_id(&id, i);
|
||||
set_turbo_mode_for_cpu(&id, enable);
|
||||
set_turbo_mode_for_cpu(&id, disable);
|
||||
}
|
||||
|
||||
}
|
||||
@ -2573,6 +2633,9 @@ static void get_set_trl(struct isst_id *id, void *arg1, void *arg2, void *arg3,
|
||||
int set = *(int *)arg4;
|
||||
int ret;
|
||||
|
||||
if (id->cpu < 0)
|
||||
return;
|
||||
|
||||
if (set && !fact_trl) {
|
||||
isst_display_error_info_message(1, "Invalid TRL. Specify with [-t|--trl]", 0, 0);
|
||||
exit(0);
|
||||
@ -2596,7 +2659,7 @@ static void process_trl(int arg)
|
||||
if (cmd_help) {
|
||||
if (arg) {
|
||||
fprintf(stderr, "Set TRL (turbo ratio limits)\n");
|
||||
fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL\n");
|
||||
fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL in hex starting with 0x\n");
|
||||
} else {
|
||||
fprintf(stderr, "Get TRL (turbo ratio limits)\n");
|
||||
}
|
||||
@ -2730,6 +2793,43 @@ error:
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void check_optarg(char *option, int hex)
|
||||
{
|
||||
if (optarg) {
|
||||
char *start = optarg;
|
||||
int i;
|
||||
|
||||
if (hex && strlen(optarg) < 3) {
|
||||
/* At least 0x plus one character must be present */
|
||||
fprintf(stderr, "malformed arguments for:%s [%s]\n", option, optarg);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (hex) {
|
||||
if (optarg[0] != '0' || tolower(optarg[1]) != 'x') {
|
||||
fprintf(stderr, "malformed arguments for:%s [%s]\n",
|
||||
option, optarg);
|
||||
exit(0);
|
||||
}
|
||||
start = &optarg[2];
|
||||
}
|
||||
|
||||
for (i = 0; i < strlen(start); ++i) {
|
||||
if (hex) {
|
||||
if (!isxdigit(start[i])) {
|
||||
fprintf(stderr, "malformed arguments for:%s [%s]\n",
|
||||
option, optarg);
|
||||
exit(0);
|
||||
}
|
||||
} else if (!isdigit(start[i])) {
|
||||
fprintf(stderr, "malformed arguments for:%s [%s]\n",
|
||||
option, optarg);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_cmd_args(int argc, int start, char **argv)
|
||||
{
|
||||
int opt;
|
||||
@ -2763,18 +2863,21 @@ static void parse_cmd_args(int argc, int start, char **argv)
|
||||
auto_mode = 1;
|
||||
break;
|
||||
case 'b':
|
||||
check_optarg("bucket", 0);
|
||||
fact_bucket = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
cmd_help = 1;
|
||||
break;
|
||||
case 'l':
|
||||
check_optarg("level", 0);
|
||||
tdp_level = atoi(optarg);
|
||||
break;
|
||||
case 'o':
|
||||
force_online_offline = 1;
|
||||
break;
|
||||
case 't':
|
||||
check_optarg("trl", 1);
|
||||
sscanf(optarg, "0x%llx", &fact_trl);
|
||||
break;
|
||||
case 'r':
|
||||
@ -2791,13 +2894,16 @@ static void parse_cmd_args(int argc, int start, char **argv)
|
||||
break;
|
||||
/* CLOS related */
|
||||
case 'c':
|
||||
check_optarg("clos", 0);
|
||||
current_clos = atoi(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
check_optarg("desired", 0);
|
||||
clos_desired = atoi(optarg);
|
||||
clos_desired /= isst_get_disp_freq_multiplier();
|
||||
break;
|
||||
case 'e':
|
||||
check_optarg("epp", 0);
|
||||
clos_epp = atoi(optarg);
|
||||
if (is_skx_based_platform()) {
|
||||
isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0);
|
||||
@ -2805,14 +2911,17 @@ static void parse_cmd_args(int argc, int start, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
check_optarg("min", 0);
|
||||
clos_min = atoi(optarg);
|
||||
clos_min /= isst_get_disp_freq_multiplier();
|
||||
break;
|
||||
case 'm':
|
||||
check_optarg("max", 0);
|
||||
clos_max = atoi(optarg);
|
||||
clos_max /= isst_get_disp_freq_multiplier();
|
||||
break;
|
||||
case 'p':
|
||||
check_optarg("priority", 0);
|
||||
clos_priority_type = atoi(optarg);
|
||||
if (is_skx_based_platform() && !clos_priority_type) {
|
||||
isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0);
|
||||
@ -2820,6 +2929,7 @@ static void parse_cmd_args(int argc, int start, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
check_optarg("weight", 0);
|
||||
clos_prop_prio = atoi(optarg);
|
||||
if (is_skx_based_platform()) {
|
||||
isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0);
|
||||
@ -2995,6 +3105,7 @@ static void usage(void)
|
||||
printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n");
|
||||
printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n");
|
||||
printf("\t[-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline.\n");
|
||||
printf("\t[-u|--cpu0-workaround : Don't try to online/offline CPU0 instead use cgroup v2.\n");
|
||||
printf("\nResult format\n");
|
||||
printf("\tResult display uses a common format for each command:\n");
|
||||
printf("\tResults are formatted in text/JSON with\n");
|
||||
@ -3048,6 +3159,7 @@ static void cmdline(int argc, char **argv)
|
||||
{ "no-daemon", no_argument, 0, 'n' },
|
||||
{ "poll-interval", required_argument, 0, 'w' },
|
||||
{ "cgroupv2", required_argument, 0, 'g' },
|
||||
{ "cpu0-workaround", required_argument, 0, 'u' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@ -3078,7 +3190,7 @@ static void cmdline(int argc, char **argv)
|
||||
goto out;
|
||||
|
||||
progname = argv[0];
|
||||
while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ng", long_options,
|
||||
while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ngu", long_options,
|
||||
&option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
@ -3140,6 +3252,9 @@ static void cmdline(int argc, char **argv)
|
||||
case 'g':
|
||||
cgroupv2 = 1;
|
||||
break;
|
||||
case 'u':
|
||||
cpu_0_cgroupv2 = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
@ -90,7 +90,8 @@ void process_level_change(struct isst_id *id)
|
||||
if (ret)
|
||||
goto use_offline;
|
||||
|
||||
isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, pkg_dev.current_level);
|
||||
isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask,
|
||||
pkg_dev.current_level, 0);
|
||||
|
||||
goto free_mask;
|
||||
}
|
||||
|
@ -318,7 +318,8 @@ extern struct isst_platform_ops *tpmi_get_platform_ops(void);
|
||||
|
||||
/* Cgroup related interface */
|
||||
extern int enable_cpuset_controller(void);
|
||||
extern int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level);
|
||||
extern int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask,
|
||||
int level, int cpu_0_only);
|
||||
extern int use_cgroupv2(void);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user