mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
platform-drivers-x86 for v6.3-1
Highlights: - AMD PMC: Improvements to aid s2idle debugging - Dell WMI-DDV: hwmon support - INT3472 camera sensor power-management: Improve privacy LED support - Intel VSEC: Base TPMI (Topology Aware Register and PM Capsule Interface) support - Mellanox: SN5600 and Nvidia L1 switch support - Microsoft Surface Support: Various cleanups + code improvements - tools/intel-speed-select: Various improvements - Miscellaneous other cleanups / fixes The following is an automated git shortlog grouped by driver: Add include/linux/platform_data/x86 to MAINTAINERS: - Add include/linux/platform_data/x86 to MAINTAINERS Documentation/ABI: - Add new attribute for mlxreg-io sysfs interfaces Fix header inclusion in linux/platform_data/x86/soc.h: - Fix header inclusion in linux/platform_data/x86/soc.h HID: - surface-hid: Use target-ID enum instead of hard-coding values MAINTAINERS: - dell-wmi-sysman: drop Divya Bharathi - Add entry for TPMI driver Merge tag 'ib-leds-led_get-v6.3' into HEAD: - Merge tag 'ib-leds-led_get-v6.3' into HEAD acerhdf: - Drop empty platform remove function apple_gmux: - Drop no longer used ACPI_VIDEO Kconfig dependency dell-ddv: - Prefer asynchronous probing - Add hwmon support - Add "force" module param - Replace EIO with ENOMSG - Return error if buffer is empty - Add support for interface version 3 dell-smo8800: - Use min_t() for comparison and assignment dell-wmi-sysman: - Make kobj_type structure constant hp-wmi: - Ignore Win-Lock key events int1092: - Switch to use acpi_evaluate_dsm_typed() int3472/discrete: - add LEDS_CLASS dependency - Drop unnecessary obj->type == string check - Get the polarity from the _DSM entry - Move GPIO request to skl_int3472_register_clock() - Create a LED class device for the privacy LED - Refactor GPIO to sensor mapping intel: - punit_ipc: Drop empty platform remove function - oaktrail: Drop empty platform remove function intel/pmc: - Switch to use acpi_evaluate_dsm_typed() leds: - led-class: Add generic [devm_]led_get() - led-class: Add __devm_led_get() helper - led-class: Add led_module_get() helper - led-class: Add missing put_device() to led_put() media: - v4l2-core: Make the v4l2-core code enable/disable the privacy LED if present nvidia-wmi-ec-backlight: - Add force module parameter platform: - mellanox: mlx-platform: Move bus shift assignment out of the loop - mellanox: mlx-platform: Add mux selection register to regmap - mellanox: Extend all systems with I2C notification callback - mellanox: Split logic in init and exit flow - mellanox: Split initialization procedure - mellanox: Introduce support of new Nvidia L1 switch - mellanox: Introduce support for next-generation 800GB/s switch - mellanox: Cosmetic changes - rename to more common name - mellanox: Change "reset_pwr_converter_fail" attribute - mellanox: Introduce support for rack manager switch platform/mellanox: - mlxreg-hotplug: Allow more flexible hotplug events configuration platform/surface: - Switch to use acpi_evaluate_dsm_typed() - aggregator: Rename top-level request functions to avoid ambiguities - aggregator_registry: Fix target-ID of base-hub - aggregator: Enforce use of target-ID enum in device ID macros - dtx: Use target-ID enum instead of hard-coding values - aggregator_tabletsw: Use target-ID enum instead of hard-coding values - aggregator_hub: Use target-ID enum instead of hard-coding values - aggregator: Add target and source IDs to command trace events - aggregator: Improve documentation and handling of message target and source IDs platform/x86/amd: - pmc: Add line break for readability - pmc: differentiate STB/SMU messaging prints - pmc: Write dummy postcode into the STB DRAM - pmc: Add num_samples message id support to STB platform/x86/amd/pmf: - Add depends on CONFIG_POWER_SUPPLY platform/x86/intel: - Intel TPMI enumeration driver platform/x86/intel/tpmi: - ADD tpmi external interface for tpmi feature drivers - Process CPU package mapping platform/x86/intel/vsec: - Use mutex for ida_alloc() and ida_free() - Support private data - Enhance and Export intel_vsec_add_aux() - Add TPMI ID platform_data/mlxreg: - Add field with mapped resource address think-lmi: - Make kobj_type structure constant - Use min_t() for comparison and assignment tools/power/x86/intel-speed-select: - v1.14 release - Adjust uncore max/min frequency - Add Emerald Rapid quirk - Fix display of uncore min frequency - turbo-freq auto mode with SMT off - cpufreq reads on offline CPUs - Use null-terminated string - Remove duplicate dup() - Handle open() failure case - Remove unused non_block flag - Remove wrong check in set_isst_id() x86/platform/uv: - Make kobj_type structure constant -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmPzRpgUHGhkZWdvZWRl QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9wYPwf+I6PP0XBg8MrivLc2DHklVojUU0aX /M0LbCP8gxCDdyisV8swC3e848riaTchYlUGASPZu0ieas1U7KsDvghkiittNvlI U+0h7TbkOQNymM8oE0oauflH4W5KwCXGrLsJWVkGk0lhJd6WmjXkjWLkruaXazLd kc5fq0QyzRVzhhCtocQ7qhIgXSZyKYx433VqbDR7/SUi5F2wkC9JbGY02maKWaK3 4lQaoyMKLjGlDr9YVv+UHTwLoXwP0mW/fjlsZ3Xz5lz6WfihQzPuOrl/10mRj0Ez eP9dlF1Dipee4BYS2FM5dtk5xPpqdVqRlQUX2qKzyDNTSx5wdtJnv8j/cg== =VoXq -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86 Pull x86 platform driver updates from Hans de Goede: - AMD PMC: Improvements to aid s2idle debugging - Dell WMI-DDV: hwmon support - INT3472 camera sensor power-management: Improve privacy LED support - Intel VSEC: Base TPMI (Topology Aware Register and PM Capsule Interface) support - Mellanox: SN5600 and Nvidia L1 switch support - Microsoft Surface Support: Various cleanups + code improvements - tools/intel-speed-select: Various improvements - Miscellaneous other cleanups / fixes * tag 'platform-drivers-x86-v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (80 commits) platform/x86: nvidia-wmi-ec-backlight: Add force module parameter platform/x86/amd/pmf: Add depends on CONFIG_POWER_SUPPLY platform/x86: dell-ddv: Prefer asynchronous probing platform/x86: dell-ddv: Add hwmon support Documentation/ABI: Add new attribute for mlxreg-io sysfs interfaces platform: mellanox: mlx-platform: Move bus shift assignment out of the loop platform: mellanox: mlx-platform: Add mux selection register to regmap platform_data/mlxreg: Add field with mapped resource address platform/mellanox: mlxreg-hotplug: Allow more flexible hotplug events configuration platform: mellanox: Extend all systems with I2C notification callback platform: mellanox: Split logic in init and exit flow platform: mellanox: Split initialization procedure platform: mellanox: Introduce support of new Nvidia L1 switch platform: mellanox: Introduce support for next-generation 800GB/s switch platform: mellanox: Cosmetic changes - rename to more common name platform: mellanox: Change "reset_pwr_converter_fail" attribute platform: mellanox: Introduce support for rack manager switch MAINTAINERS: dell-wmi-sysman: drop Divya Bharathi x86/platform/uv: Make kobj_type structure constant platform/x86: think-lmi: Make kobj_type structure constant ...
This commit is contained in:
commit
69308402ca
@ -522,7 +522,6 @@ Description: These files allow to each of ASICs by writing 1.
|
||||
|
||||
The files are write only.
|
||||
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/comm_chnl_ready
|
||||
Date: July 2022
|
||||
KernelVersion: 5.20
|
||||
@ -542,3 +541,124 @@ Description: The file indicates COME module hardware configuration.
|
||||
The purpose is to expose some minor BOM changes for the same system SKU.
|
||||
|
||||
The file is read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_pwr_converter_fail
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak <vadimp@nvidia.com>
|
||||
Description: This file shows the system reset cause due to power converter
|
||||
devices failure.
|
||||
Value 1 in file means this is reset cause, 0 - otherwise.
|
||||
|
||||
The file is read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_ap_reset
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_ap_reset
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak <vadimp@nvidia.com>
|
||||
Description: These files aim to monitor the status of the External Root of Trust (EROT)
|
||||
processor's RESET output to the Application Processor (AP).
|
||||
By reading this file, could be determined if the EROT has invalidated or
|
||||
revoked AP Firmware, at which point it will hold the AP in RESET until a
|
||||
valid firmware is loaded. This protects the AP from running an
|
||||
unauthorized firmware. In the normal flow, the AP reset should be released
|
||||
after the EROT validates the integrity of the FW, and it should be done so
|
||||
as quickly as possible so that the AP boots before the CPU starts to
|
||||
communicate to each ASIC.
|
||||
|
||||
The files are read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_recovery
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_recovery
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_reset
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_reset
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak <vadimp@nvidia.com>
|
||||
Description: These files aim to perform External Root of Trust (EROT) recovery
|
||||
sequence after EROT device failure.
|
||||
These EROT devices protect ASICs from unauthorized access and in normal
|
||||
flow their reset should be released with system power – earliest power
|
||||
up stage, so that EROTs can begin boot and authentication process before
|
||||
CPU starts to communicate to ASICs.
|
||||
Issuing a reset to the EROT while asserting the recovery signal will cause
|
||||
the EROT Application Processor to enter recovery mode so that the EROT FW
|
||||
can be updated/recovered.
|
||||
For reset/recovery the related file should be toggled by 1/0.
|
||||
|
||||
The files are read/write.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_wp
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_wp
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak <vadimp@nvidia.com>
|
||||
Description: These files allow access to External Root of Trust (EROT) for reset
|
||||
and recovery sequence after EROT device failure.
|
||||
Default is 0 (programming disabled).
|
||||
If the system is in locked-down mode writing this file will not be allowed.
|
||||
|
||||
The files are read/write.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/spi_chnl_select
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak <vadimp@nvidia.com>
|
||||
Description: This file allows SPI chip selection for External Root of Trust (EROT)
|
||||
device Out-of-Band recovery.
|
||||
File can be written with 0 or with 1. It selects which EROT can be accessed
|
||||
through SPI device.
|
||||
|
||||
The file is read/write.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_pg_fail
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak vadimp@nvidia.com
|
||||
Description: This file shows ASIC Power Good status.
|
||||
Value 1 in file means ASIC Power Good failed, 0 - otherwise.
|
||||
|
||||
The file is read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd1_boot_fail
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd2_boot_fail
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd_fail
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak vadimp@nvidia.com
|
||||
Description: These files are related to clock boards status in system.
|
||||
- clk_brd1_boot_fail: warning about 1-st clock board failed to boot from CI.
|
||||
- clk_brd2_boot_fail: warning about 2-nd clock board failed to boot from CI.
|
||||
- clk_brd_fail: error about common clock board boot failure.
|
||||
|
||||
The files are read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd_prog_en
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak <vadimp@nvidia.com>
|
||||
Description: This file enables programming of clock boards.
|
||||
Default is 0 (programming disabled).
|
||||
If the system is in locked-down mode writing this file will not be allowed.
|
||||
|
||||
The file is read/write.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pwr_converter_prog_en
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak <vadimp@nvidia.com>
|
||||
Description: This file enables programming of power converters.
|
||||
Default is 0 (programming disabled).
|
||||
If the system is in locked-down mode writing this file will not be allowed.
|
||||
|
||||
The file is read/write.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_ac_ok_fail
|
||||
Date: February 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: Vadim Pasternak <vadimp@nvidia.com>
|
||||
Description: This file shows the system reset cause due to AC power failure.
|
||||
Value 1 in file means this is reset cause, 0 - otherwise.
|
||||
|
||||
The file is read only.
|
||||
|
@ -19,7 +19,7 @@
|
||||
.. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
|
||||
.. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register`
|
||||
.. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister`
|
||||
.. |ssam_request_sync| replace:: :c:func:`ssam_request_sync`
|
||||
.. |ssam_request_do_sync| replace:: :c:func:`ssam_request_do_sync`
|
||||
.. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>`
|
||||
|
||||
|
||||
@ -191,7 +191,7 @@ data received from it is converted from little-endian to host endianness.
|
||||
* they do not correspond to an actual SAM/EC request.
|
||||
*/
|
||||
rqst.target_category = SSAM_SSH_TC_SAM;
|
||||
rqst.target_id = 0x01;
|
||||
rqst.target_id = SSAM_SSH_TID_SAM;
|
||||
rqst.command_id = 0x02;
|
||||
rqst.instance_id = 0x03;
|
||||
rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
|
||||
@ -209,12 +209,12 @@ data received from it is converted from little-endian to host endianness.
|
||||
* with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification
|
||||
* above.
|
||||
*/
|
||||
status = ssam_request_sync(ctrl, &rqst, &resp);
|
||||
status = ssam_request_do_sync(ctrl, &rqst, &resp);
|
||||
|
||||
/*
|
||||
* Alternatively use
|
||||
*
|
||||
* ssam_request_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le));
|
||||
* ssam_request_do_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le));
|
||||
*
|
||||
* to perform the request, allocating the message buffer directly
|
||||
* on the stack as opposed to allocation via kzalloc().
|
||||
@ -230,7 +230,7 @@ data received from it is converted from little-endian to host endianness.
|
||||
return status;
|
||||
}
|
||||
|
||||
Note that |ssam_request_sync| in its essence is a wrapper over lower-level
|
||||
Note that |ssam_request_do_sync| in its essence is a wrapper over lower-level
|
||||
request primitives, which may also be used to perform requests. Refer to its
|
||||
implementation and documentation for more details.
|
||||
|
||||
@ -241,7 +241,7 @@ one of the generator macros, for example via:
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, {
|
||||
.target_category = SSAM_SSH_TC_TMP,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x03,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
@ -13,6 +13,7 @@
|
||||
.. |DATA_NSQ| replace:: ``DATA_NSQ``
|
||||
.. |TC| replace:: ``TC``
|
||||
.. |TID| replace:: ``TID``
|
||||
.. |SID| replace:: ``SID``
|
||||
.. |IID| replace:: ``IID``
|
||||
.. |RQID| replace:: ``RQID``
|
||||
.. |CID| replace:: ``CID``
|
||||
@ -219,13 +220,13 @@ following fields, packed together and in order:
|
||||
- |u8|
|
||||
- Target category.
|
||||
|
||||
* - |TID| (out)
|
||||
* - |TID|
|
||||
- |u8|
|
||||
- Target ID for outgoing (host to EC) commands.
|
||||
- Target ID for commands/messages.
|
||||
|
||||
* - |TID| (in)
|
||||
* - |SID|
|
||||
- |u8|
|
||||
- Target ID for incoming (EC to host) commands.
|
||||
- Source ID for commands/messages.
|
||||
|
||||
* - |IID|
|
||||
- |u8|
|
||||
@ -286,19 +287,20 @@ general, however, a single target category should map to a single reserved
|
||||
event request ID.
|
||||
|
||||
Furthermore, requests, responses, and events have an associated target ID
|
||||
(``TID``). This target ID is split into output (host to EC) and input (EC to
|
||||
host) fields, with the respecting other field (e.g. output field on incoming
|
||||
messages) set to zero. Two ``TID`` values are known: Primary (``0x01``) and
|
||||
secondary (``0x02``). In general, the response to a request should have the
|
||||
same ``TID`` value, however, the field (output vs. input) should be used in
|
||||
accordance to the direction in which the response is sent (i.e. on the input
|
||||
field, as responses are generally sent from the EC to the host).
|
||||
(``TID``) and source ID (``SID``). These two fields indicate where a message
|
||||
originates from (``SID``) and what the intended target of the message is
|
||||
(``TID``). Note that a response to a specific request therefore has the source
|
||||
and target IDs swapped when compared to the original request (i.e. the request
|
||||
target is the response source and the request source is the response target).
|
||||
See (:c:type:`enum ssh_request_id <ssh_request_id>`) for possible values of
|
||||
both.
|
||||
|
||||
Note that, even though requests and events should be uniquely identifiable
|
||||
by target category and command ID alone, the EC may require specific
|
||||
target ID and instance ID values to accept a command. A command that is
|
||||
accepted for ``TID=1``, for example, may not be accepted for ``TID=2``
|
||||
and vice versa.
|
||||
Note that, even though requests and events should be uniquely identifiable by
|
||||
target category and command ID alone, the EC may require specific target ID and
|
||||
instance ID values to accept a command. A command that is accepted for
|
||||
``TID=1``, for example, may not be accepted for ``TID=2`` and vice versa. While
|
||||
this may not always hold in reality, you can think of different target/source
|
||||
IDs indicating different physical ECs with potentially different feature sets.
|
||||
|
||||
|
||||
Limitations and Observations
|
||||
|
@ -5773,7 +5773,6 @@ F: Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
|
||||
F: drivers/platform/x86/dell/dell-wmi-ddv.c
|
||||
|
||||
DELL WMI SYSMAN DRIVER
|
||||
M: Divya Bharathi <divya.bharathi@dell.com>
|
||||
M: Prasanth Ksr <prasanth.ksr@dell.com>
|
||||
L: Dell.Client.Kernel@dell.com
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
@ -10535,6 +10534,13 @@ S: Maintained
|
||||
F: arch/x86/include/asm/intel_telemetry.h
|
||||
F: drivers/platform/x86/intel/telemetry/
|
||||
|
||||
INTEL TPMI DRIVER
|
||||
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/intel/tpmi.c
|
||||
F: include/linux/intel_tpmi.h
|
||||
|
||||
INTEL UNCORE FREQUENCY CONTROL
|
||||
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
@ -22480,6 +22486,7 @@ S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
|
||||
F: drivers/platform/olpc/
|
||||
F: drivers/platform/x86/
|
||||
F: include/linux/platform_data/x86/
|
||||
|
||||
X86 PLATFORM DRIVERS - ARCH
|
||||
R: Darren Hart <dvhart@infradead.org>
|
||||
|
@ -80,7 +80,7 @@ static int ssam_hid_get_descriptor(struct surface_hid_device *shid, u8 entry, u8
|
||||
|
||||
rsp.length = 0;
|
||||
|
||||
status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp,
|
||||
status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp,
|
||||
sizeof(*slice));
|
||||
if (status)
|
||||
return status;
|
||||
@ -131,7 +131,7 @@ static int ssam_hid_set_raw_report(struct surface_hid_device *shid, u8 rprt_id,
|
||||
|
||||
buf[0] = rprt_id;
|
||||
|
||||
return ssam_retry(ssam_request_sync, shid->ctrl, &rqst, NULL);
|
||||
return ssam_retry(ssam_request_do_sync, shid->ctrl, &rqst, NULL);
|
||||
}
|
||||
|
||||
static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
|
||||
@ -151,7 +151,7 @@ static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id,
|
||||
rsp.length = 0;
|
||||
rsp.pointer = buf;
|
||||
|
||||
return ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(rprt_id));
|
||||
return ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(rprt_id));
|
||||
}
|
||||
|
||||
static u32 ssam_hid_event_fn(struct ssam_event_notifier *nf, const struct ssam_event *event)
|
||||
@ -230,7 +230,7 @@ static void surface_hid_remove(struct ssam_device *sdev)
|
||||
}
|
||||
|
||||
static const struct ssam_device_id surface_hid_match[] = {
|
||||
{ SSAM_SDEV(HID, SSAM_ANY_TID, SSAM_ANY_IID, 0x00) },
|
||||
{ SSAM_SDEV(HID, ANY, SSAM_SSH_IID_ANY, 0x00) },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssam, surface_hid_match);
|
||||
|
@ -49,7 +49,7 @@ static int ssam_kbd_get_descriptor(struct surface_hid_device *shid, u8 entry, u8
|
||||
rsp.length = 0;
|
||||
rsp.pointer = buf;
|
||||
|
||||
status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(entry));
|
||||
status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(entry));
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@ -75,7 +75,7 @@ static int ssam_kbd_set_caps_led(struct surface_hid_device *shid, bool value)
|
||||
rqst.length = sizeof(value_u8);
|
||||
rqst.payload = &value_u8;
|
||||
|
||||
return ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, NULL, sizeof(value_u8));
|
||||
return ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, NULL, sizeof(value_u8));
|
||||
}
|
||||
|
||||
static int ssam_kbd_get_feature_report(struct surface_hid_device *shid, u8 *buf, size_t len)
|
||||
@ -97,7 +97,7 @@ static int ssam_kbd_get_feature_report(struct surface_hid_device *shid, u8 *buf,
|
||||
rsp.length = 0;
|
||||
rsp.pointer = buf;
|
||||
|
||||
status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(payload));
|
||||
status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(payload));
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@ -250,7 +250,7 @@ static int surface_kbd_probe(struct platform_device *pdev)
|
||||
|
||||
shid->uid.domain = SSAM_DOMAIN_SERIALHUB;
|
||||
shid->uid.category = SSAM_SSH_TC_KBD;
|
||||
shid->uid.target = 2;
|
||||
shid->uid.target = SSAM_SSH_TID_KIP;
|
||||
shid->uid.instance = 0;
|
||||
shid->uid.function = 0;
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "leds.h"
|
||||
|
||||
static struct class *leds_class;
|
||||
static DEFINE_MUTEX(leds_lookup_lock);
|
||||
static LIST_HEAD(leds_lookup_list);
|
||||
|
||||
static ssize_t brightness_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@ -215,6 +217,23 @@ static int led_resume(struct device *dev)
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
|
||||
|
||||
static struct led_classdev *led_module_get(struct device *led_dev)
|
||||
{
|
||||
struct led_classdev *led_cdev;
|
||||
|
||||
if (!led_dev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
led_cdev = dev_get_drvdata(led_dev);
|
||||
|
||||
if (!try_module_get(led_cdev->dev->parent->driver->owner)) {
|
||||
put_device(led_cdev->dev);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
return led_cdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_led_get() - request a LED device via the LED framework
|
||||
* @np: device node to get the LED device from
|
||||
@ -226,7 +245,6 @@ static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
|
||||
struct led_classdev *of_led_get(struct device_node *np, int index)
|
||||
{
|
||||
struct device *led_dev;
|
||||
struct led_classdev *led_cdev;
|
||||
struct device_node *led_node;
|
||||
|
||||
led_node = of_parse_phandle(np, "leds", index);
|
||||
@ -236,15 +254,7 @@ struct led_classdev *of_led_get(struct device_node *np, int index)
|
||||
led_dev = class_find_device_by_of_node(leds_class, led_node);
|
||||
of_node_put(led_node);
|
||||
|
||||
if (!led_dev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
led_cdev = dev_get_drvdata(led_dev);
|
||||
|
||||
if (!try_module_get(led_cdev->dev->parent->driver->owner))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return led_cdev;
|
||||
return led_module_get(led_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_led_get);
|
||||
|
||||
@ -255,6 +265,7 @@ EXPORT_SYMBOL_GPL(of_led_get);
|
||||
void led_put(struct led_classdev *led_cdev)
|
||||
{
|
||||
module_put(led_cdev->dev->parent->driver->owner);
|
||||
put_device(led_cdev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_put);
|
||||
|
||||
@ -265,6 +276,22 @@ static void devm_led_release(struct device *dev, void *res)
|
||||
led_put(*p);
|
||||
}
|
||||
|
||||
static struct led_classdev *__devm_led_get(struct device *dev, struct led_classdev *led)
|
||||
{
|
||||
struct led_classdev **dr;
|
||||
|
||||
dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *), GFP_KERNEL);
|
||||
if (!dr) {
|
||||
led_put(led);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
*dr = led;
|
||||
devres_add(dev, dr);
|
||||
|
||||
return led;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_of_led_get - Resource-managed request of a LED device
|
||||
* @dev: LED consumer
|
||||
@ -280,7 +307,6 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev,
|
||||
int index)
|
||||
{
|
||||
struct led_classdev *led;
|
||||
struct led_classdev **dr;
|
||||
|
||||
if (!dev)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -289,20 +315,92 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev,
|
||||
if (IS_ERR(led))
|
||||
return led;
|
||||
|
||||
dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *),
|
||||
GFP_KERNEL);
|
||||
if (!dr) {
|
||||
led_put(led);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
*dr = led;
|
||||
devres_add(dev, dr);
|
||||
|
||||
return led;
|
||||
return __devm_led_get(dev, led);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_of_led_get);
|
||||
|
||||
/**
|
||||
* led_get() - request a LED device via the LED framework
|
||||
* @dev: device for which to get the LED device
|
||||
* @con_id: name of the LED from the device's point of view
|
||||
*
|
||||
* @return a pointer to a LED device or ERR_PTR(errno) on failure.
|
||||
*/
|
||||
struct led_classdev *led_get(struct device *dev, char *con_id)
|
||||
{
|
||||
struct led_lookup_data *lookup;
|
||||
const char *provider = NULL;
|
||||
struct device *led_dev;
|
||||
|
||||
mutex_lock(&leds_lookup_lock);
|
||||
list_for_each_entry(lookup, &leds_lookup_list, list) {
|
||||
if (!strcmp(lookup->dev_id, dev_name(dev)) &&
|
||||
!strcmp(lookup->con_id, con_id)) {
|
||||
provider = kstrdup_const(lookup->provider, GFP_KERNEL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&leds_lookup_lock);
|
||||
|
||||
if (!provider)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
led_dev = class_find_device_by_name(leds_class, provider);
|
||||
kfree_const(provider);
|
||||
|
||||
return led_module_get(led_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_get);
|
||||
|
||||
/**
|
||||
* devm_led_get() - request a LED device via the LED framework
|
||||
* @dev: device for which to get the LED device
|
||||
* @con_id: name of the LED from the device's point of view
|
||||
*
|
||||
* The LED device returned from this function is automatically released
|
||||
* on driver detach.
|
||||
*
|
||||
* @return a pointer to a LED device or ERR_PTR(errno) on failure.
|
||||
*/
|
||||
struct led_classdev *devm_led_get(struct device *dev, char *con_id)
|
||||
{
|
||||
struct led_classdev *led;
|
||||
|
||||
led = led_get(dev, con_id);
|
||||
if (IS_ERR(led))
|
||||
return led;
|
||||
|
||||
return __devm_led_get(dev, led);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_led_get);
|
||||
|
||||
/**
|
||||
* led_add_lookup() - Add a LED lookup table entry
|
||||
* @led_lookup: the lookup table entry to add
|
||||
*
|
||||
* Add a LED lookup table entry. On systems without devicetree the lookup table
|
||||
* is used by led_get() to find LEDs.
|
||||
*/
|
||||
void led_add_lookup(struct led_lookup_data *led_lookup)
|
||||
{
|
||||
mutex_lock(&leds_lookup_lock);
|
||||
list_add_tail(&led_lookup->list, &leds_lookup_list);
|
||||
mutex_unlock(&leds_lookup_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_add_lookup);
|
||||
|
||||
/**
|
||||
* led_remove_lookup() - Remove a LED lookup table entry
|
||||
* @led_lookup: the lookup table entry to remove
|
||||
*/
|
||||
void led_remove_lookup(struct led_lookup_data *led_lookup)
|
||||
{
|
||||
mutex_lock(&leds_lookup_lock);
|
||||
list_del(&led_lookup->list);
|
||||
mutex_unlock(&leds_lookup_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_remove_lookup);
|
||||
|
||||
static int led_classdev_next_name(const char *init_name, char *name,
|
||||
size_t len)
|
||||
{
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "v4l2-subdev-priv.h"
|
||||
|
||||
static int v4l2_async_nf_call_bound(struct v4l2_async_notifier *n,
|
||||
struct v4l2_subdev *subdev,
|
||||
struct v4l2_async_subdev *asd)
|
||||
@ -822,6 +824,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
|
||||
if (!sd->async_list.next)
|
||||
return;
|
||||
|
||||
v4l2_subdev_put_privacy_led(sd);
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
__v4l2_async_nf_unregister(sd->subdev_notifier);
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "v4l2-subdev-priv.h"
|
||||
|
||||
static const struct v4l2_fwnode_bus_conv {
|
||||
enum v4l2_fwnode_bus_type fwnode_bus_type;
|
||||
enum v4l2_mbus_type mbus_type;
|
||||
@ -1302,6 +1304,10 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
|
||||
|
||||
v4l2_async_nf_init(notifier);
|
||||
|
||||
ret = v4l2_subdev_get_privacy_led(sd);
|
||||
if (ret < 0)
|
||||
goto out_cleanup;
|
||||
|
||||
ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier);
|
||||
if (ret < 0)
|
||||
goto out_cleanup;
|
||||
@ -1322,6 +1328,7 @@ out_unregister:
|
||||
v4l2_async_nf_unregister(notifier);
|
||||
|
||||
out_cleanup:
|
||||
v4l2_subdev_put_privacy_led(sd);
|
||||
v4l2_async_nf_cleanup(notifier);
|
||||
kfree(notifier);
|
||||
|
||||
|
14
drivers/media/v4l2-core/v4l2-subdev-priv.h
Normal file
14
drivers/media/v4l2-core/v4l2-subdev-priv.h
Normal file
@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* V4L2 sub-device pivate header.
|
||||
*
|
||||
* Copyright (C) 2023 Hans de Goede <hdegoede@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef _V4L2_SUBDEV_PRIV_H_
|
||||
#define _V4L2_SUBDEV_PRIV_H_
|
||||
|
||||
int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd);
|
||||
void v4l2_subdev_put_privacy_led(struct v4l2_subdev *sd);
|
||||
|
||||
#endif
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
@ -23,6 +24,8 @@
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-event.h>
|
||||
|
||||
#include "v4l2-subdev-priv.h"
|
||||
|
||||
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
|
||||
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
|
||||
{
|
||||
@ -322,6 +325,15 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
|
||||
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
|
||||
if (enable)
|
||||
led_set_brightness(sd->privacy_led,
|
||||
sd->privacy_led->max_brightness);
|
||||
else
|
||||
led_set_brightness(sd->privacy_led, 0);
|
||||
}
|
||||
#endif
|
||||
ret = sd->ops->video->s_stream(sd, enable);
|
||||
|
||||
if (!enable && ret < 0) {
|
||||
@ -1090,6 +1102,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
|
||||
sd->grp_id = 0;
|
||||
sd->dev_priv = NULL;
|
||||
sd->host_priv = NULL;
|
||||
sd->privacy_led = NULL;
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
sd->entity.name = sd->name;
|
||||
sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
|
||||
@ -1105,3 +1118,36 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
|
||||
v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, (void *)ev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event);
|
||||
|
||||
int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd)
|
||||
{
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
|
||||
sd->privacy_led = led_get(sd->dev, "privacy-led");
|
||||
if (IS_ERR(sd->privacy_led) && PTR_ERR(sd->privacy_led) != -ENOENT)
|
||||
return dev_err_probe(sd->dev, PTR_ERR(sd->privacy_led),
|
||||
"getting privacy LED\n");
|
||||
|
||||
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
|
||||
mutex_lock(&sd->privacy_led->led_access);
|
||||
led_sysfs_disable(sd->privacy_led);
|
||||
led_trigger_remove(sd->privacy_led);
|
||||
led_set_brightness(sd->privacy_led, 0);
|
||||
mutex_unlock(&sd->privacy_led->led_access);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_get_privacy_led);
|
||||
|
||||
void v4l2_subdev_put_privacy_led(struct v4l2_subdev *sd)
|
||||
{
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
|
||||
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
|
||||
mutex_lock(&sd->privacy_led->led_access);
|
||||
led_sysfs_enable(sd->privacy_led);
|
||||
mutex_unlock(&sd->privacy_led->led_access);
|
||||
led_put(sd->privacy_led);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_put_privacy_led);
|
||||
|
@ -239,6 +239,17 @@ static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
|
||||
#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
|
||||
#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
|
||||
|
||||
static int mlxreg_hotplug_item_label_index_get(u32 mask, u32 bit)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0, j = -1; i <= bit; i++) {
|
||||
if (mask & BIT(i))
|
||||
j++;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
|
||||
{
|
||||
struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
@ -246,7 +257,7 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
|
||||
struct mlxreg_core_data *data;
|
||||
unsigned long mask;
|
||||
u32 regval;
|
||||
int num_attrs = 0, id = 0, i, j, k, ret;
|
||||
int num_attrs = 0, id = 0, i, j, k, count, ret;
|
||||
|
||||
pdata = dev_get_platdata(&priv->pdev->dev);
|
||||
item = pdata->items;
|
||||
@ -272,7 +283,8 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
|
||||
/* Go over all unmasked units within item. */
|
||||
mask = item->mask;
|
||||
k = 0;
|
||||
for_each_set_bit(j, &mask, item->count) {
|
||||
count = item->ind ? item->ind : item->count;
|
||||
for_each_set_bit(j, &mask, count) {
|
||||
if (data->capability) {
|
||||
/*
|
||||
* Read capability register and skip non
|
||||
@ -282,16 +294,17 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
|
||||
data->capability, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(regval & data->bit)) {
|
||||
data++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
|
||||
PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
|
||||
GFP_KERNEL,
|
||||
data->label);
|
||||
|
||||
if (!PRIV_ATTR(id)->name) {
|
||||
dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
|
||||
id);
|
||||
@ -365,9 +378,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
|
||||
regval &= item->mask;
|
||||
asserted = item->cache ^ regval;
|
||||
item->cache = regval;
|
||||
|
||||
for_each_set_bit(bit, &asserted, 8) {
|
||||
data = item->data + bit;
|
||||
int pos;
|
||||
|
||||
pos = mlxreg_hotplug_item_label_index_get(item->mask, bit);
|
||||
if (pos < 0)
|
||||
goto out;
|
||||
|
||||
data = item->data + pos;
|
||||
if (regval & BIT(bit)) {
|
||||
if (item->inversed)
|
||||
mlxreg_hotplug_device_destroy(priv, data, item->kind);
|
||||
|
@ -136,9 +136,9 @@ int ssam_device_add(struct ssam_device *sdev)
|
||||
* is always valid and can be used for requests as long as the client
|
||||
* device we add here is registered as child under it. This essentially
|
||||
* guarantees that the client driver can always expect the preconditions
|
||||
* for functions like ssam_request_sync (controller has to be started
|
||||
* and is not suspended) to hold and thus does not have to check for
|
||||
* them.
|
||||
* for functions like ssam_request_do_sync() (controller has to be
|
||||
* started and is not suspended) to hold and thus does not have to check
|
||||
* for them.
|
||||
*
|
||||
* Note that for this to work, the controller has to be a parent device.
|
||||
* If it is not a direct parent, care has to be taken that the device is
|
||||
|
@ -994,7 +994,7 @@ static void ssam_handle_event(struct ssh_rtl *rtl,
|
||||
|
||||
item->rqid = get_unaligned_le16(&cmd->rqid);
|
||||
item->event.target_category = cmd->tc;
|
||||
item->event.target_id = cmd->tid_in;
|
||||
item->event.target_id = cmd->sid;
|
||||
item->event.command_id = cmd->cid;
|
||||
item->event.instance_id = cmd->iid;
|
||||
memcpy(&item->event.data[0], data->ptr, data->len);
|
||||
@ -1674,7 +1674,7 @@ int ssam_request_sync_submit(struct ssam_controller *ctrl,
|
||||
EXPORT_SYMBOL_GPL(ssam_request_sync_submit);
|
||||
|
||||
/**
|
||||
* ssam_request_sync() - Execute a synchronous request.
|
||||
* ssam_request_do_sync() - Execute a synchronous request.
|
||||
* @ctrl: The controller via which the request will be submitted.
|
||||
* @spec: The request specification and payload.
|
||||
* @rsp: The response buffer.
|
||||
@ -1686,9 +1686,9 @@ EXPORT_SYMBOL_GPL(ssam_request_sync_submit);
|
||||
*
|
||||
* Return: Returns the status of the request or any failure during setup.
|
||||
*/
|
||||
int ssam_request_sync(struct ssam_controller *ctrl,
|
||||
const struct ssam_request *spec,
|
||||
struct ssam_response *rsp)
|
||||
int ssam_request_do_sync(struct ssam_controller *ctrl,
|
||||
const struct ssam_request *spec,
|
||||
struct ssam_response *rsp)
|
||||
{
|
||||
struct ssam_request_sync *rqst;
|
||||
struct ssam_span buf;
|
||||
@ -1722,10 +1722,10 @@ int ssam_request_sync(struct ssam_controller *ctrl,
|
||||
ssam_request_sync_free(rqst);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ssam_request_sync);
|
||||
EXPORT_SYMBOL_GPL(ssam_request_do_sync);
|
||||
|
||||
/**
|
||||
* ssam_request_sync_with_buffer() - Execute a synchronous request with the
|
||||
* ssam_request_do_sync_with_buffer() - Execute a synchronous request with the
|
||||
* provided buffer as back-end for the message buffer.
|
||||
* @ctrl: The controller via which the request will be submitted.
|
||||
* @spec: The request specification and payload.
|
||||
@ -1738,17 +1738,17 @@ EXPORT_SYMBOL_GPL(ssam_request_sync);
|
||||
* SSH_COMMAND_MESSAGE_LENGTH() macro can be used to compute the required
|
||||
* message buffer size.
|
||||
*
|
||||
* This function does essentially the same as ssam_request_sync(), but instead
|
||||
* of dynamically allocating the request and message data buffer, it uses the
|
||||
* provided message data buffer and stores the (small) request struct on the
|
||||
* heap.
|
||||
* This function does essentially the same as ssam_request_do_sync(), but
|
||||
* instead of dynamically allocating the request and message data buffer, it
|
||||
* uses the provided message data buffer and stores the (small) request struct
|
||||
* on the heap.
|
||||
*
|
||||
* Return: Returns the status of the request or any failure during setup.
|
||||
*/
|
||||
int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
|
||||
const struct ssam_request *spec,
|
||||
struct ssam_response *rsp,
|
||||
struct ssam_span *buf)
|
||||
int ssam_request_do_sync_with_buffer(struct ssam_controller *ctrl,
|
||||
const struct ssam_request *spec,
|
||||
struct ssam_response *rsp,
|
||||
struct ssam_span *buf)
|
||||
{
|
||||
struct ssam_request_sync rqst;
|
||||
ssize_t len;
|
||||
@ -1772,42 +1772,42 @@ int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer);
|
||||
EXPORT_SYMBOL_GPL(ssam_request_do_sync_with_buffer);
|
||||
|
||||
|
||||
/* -- Internal SAM requests. ------------------------------------------------ */
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, {
|
||||
.target_category = SSAM_SSH_TC_SAM,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x13,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, {
|
||||
.target_category = SSAM_SSH_TC_SAM,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x15,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, {
|
||||
.target_category = SSAM_SSH_TC_SAM,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x16,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, {
|
||||
.target_category = SSAM_SSH_TC_SAM,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x33,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, {
|
||||
.target_category = SSAM_SSH_TC_SAM,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x34,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
@ -1864,7 +1864,7 @@ static int __ssam_ssh_event_request(struct ssam_controller *ctrl,
|
||||
result.length = 0;
|
||||
result.pointer = &buf;
|
||||
|
||||
status = ssam_retry(ssam_request_sync_onstack, ctrl, &rqst, &result,
|
||||
status = ssam_retry(ssam_request_do_sync_onstack, ctrl, &rqst, &result,
|
||||
sizeof(params));
|
||||
|
||||
return status < 0 ? status : buf;
|
||||
|
@ -189,8 +189,8 @@ static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,
|
||||
|
||||
__msgb_push_u8(msgb, SSH_PLD_TYPE_CMD); /* Payload type. */
|
||||
__msgb_push_u8(msgb, rqst->target_category); /* Target category. */
|
||||
__msgb_push_u8(msgb, rqst->target_id); /* Target ID (out). */
|
||||
__msgb_push_u8(msgb, 0x00); /* Target ID (in). */
|
||||
__msgb_push_u8(msgb, rqst->target_id); /* Target ID. */
|
||||
__msgb_push_u8(msgb, SSAM_SSH_TID_HOST); /* Source ID. */
|
||||
__msgb_push_u8(msgb, rqst->instance_id); /* Instance ID. */
|
||||
__msgb_push_u16(msgb, rqid); /* Request ID. */
|
||||
__msgb_push_u8(msgb, rqst->command_id); /* Command ID. */
|
||||
|
@ -920,13 +920,14 @@ static void ssh_rtl_rx_command(struct ssh_ptl *p, const struct ssam_span *data)
|
||||
* Check if the message was intended for us. If not, drop it.
|
||||
*
|
||||
* Note: We will need to change this to handle debug messages. On newer
|
||||
* generation devices, these seem to be sent to tid_out=0x03. We as
|
||||
* host can still receive them as they can be forwarded via an override
|
||||
* option on SAM, but doing so does not change tid_out=0x00.
|
||||
* generation devices, these seem to be sent to SSAM_SSH_TID_DEBUG. We
|
||||
* as host can still receive them as they can be forwarded via an
|
||||
* override option on SAM, but doing so does not change the target ID
|
||||
* to SSAM_SSH_TID_HOST.
|
||||
*/
|
||||
if (command->tid_out != 0x00) {
|
||||
if (command->tid != SSAM_SSH_TID_HOST) {
|
||||
rtl_warn(rtl, "rtl: dropping message not intended for us (tid = %#04x)\n",
|
||||
command->tid_out);
|
||||
command->tid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,7 @@ TRACE_DEFINE_ENUM(SSAM_SSH_TC_POS);
|
||||
#define SSAM_SEQ_NOT_APPLICABLE ((u16)-1)
|
||||
#define SSAM_RQID_NOT_APPLICABLE ((u32)-1)
|
||||
#define SSAM_SSH_TC_NOT_APPLICABLE 0
|
||||
#define SSAM_SSH_TID_NOT_APPLICABLE ((u8)-1)
|
||||
|
||||
#ifndef _SURFACE_AGGREGATOR_TRACE_HELPERS
|
||||
#define _SURFACE_AGGREGATOR_TRACE_HELPERS
|
||||
@ -150,12 +151,44 @@ static inline u32 ssam_trace_get_request_id(const struct ssh_packet *p)
|
||||
return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(rqid)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* ssam_trace_get_request_tid() - Read the packet's request target ID.
|
||||
* @p: The packet.
|
||||
*
|
||||
* Return: Returns the packet's request target ID (TID) field if the packet
|
||||
* represents a request with command data, or %SSAM_SSH_TID_NOT_APPLICABLE
|
||||
* if not (e.g. flush request, control packet).
|
||||
*/
|
||||
static inline u32 ssam_trace_get_request_tid(const struct ssh_packet *p)
|
||||
{
|
||||
if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0))
|
||||
return SSAM_SSH_TID_NOT_APPLICABLE;
|
||||
|
||||
return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(tid)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* ssam_trace_get_request_sid() - Read the packet's request source ID.
|
||||
* @p: The packet.
|
||||
*
|
||||
* Return: Returns the packet's request source ID (SID) field if the packet
|
||||
* represents a request with command data, or %SSAM_SSH_TID_NOT_APPLICABLE
|
||||
* if not (e.g. flush request, control packet).
|
||||
*/
|
||||
static inline u32 ssam_trace_get_request_sid(const struct ssh_packet *p)
|
||||
{
|
||||
if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0))
|
||||
return SSAM_SSH_TID_NOT_APPLICABLE;
|
||||
|
||||
return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(sid)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* ssam_trace_get_request_tc() - Read the packet's request target category.
|
||||
* @p: The packet.
|
||||
*
|
||||
* Return: Returns the packet's request target category (TC) field if the
|
||||
* packet represents a request with command data, or %SSAM_TC_NOT_APPLICABLE
|
||||
* packet represents a request with command data, or %SSAM_SSH_TC_NOT_APPLICABLE
|
||||
* if not (e.g. flush request, control packet).
|
||||
*/
|
||||
static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p)
|
||||
@ -232,8 +265,18 @@ static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p)
|
||||
{ SSAM_RQID_NOT_APPLICABLE, "N/A" } \
|
||||
)
|
||||
|
||||
#define ssam_show_ssh_tc(rqid) \
|
||||
__print_symbolic(rqid, \
|
||||
#define ssam_show_ssh_tid(tid) \
|
||||
__print_symbolic(tid, \
|
||||
{ SSAM_SSH_TID_NOT_APPLICABLE, "N/A" }, \
|
||||
{ SSAM_SSH_TID_HOST, "Host" }, \
|
||||
{ SSAM_SSH_TID_SAM, "SAM" }, \
|
||||
{ SSAM_SSH_TID_KIP, "KIP" }, \
|
||||
{ SSAM_SSH_TID_DEBUG, "Debug" }, \
|
||||
{ SSAM_SSH_TID_SURFLINK, "SurfLink" } \
|
||||
)
|
||||
|
||||
#define ssam_show_ssh_tc(tc) \
|
||||
__print_symbolic(tc, \
|
||||
{ SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \
|
||||
{ SSAM_SSH_TC_SAM, "SAM" }, \
|
||||
{ SSAM_SSH_TC_BAT, "BAT" }, \
|
||||
@ -313,6 +356,8 @@ DECLARE_EVENT_CLASS(ssam_command_class,
|
||||
TP_STRUCT__entry(
|
||||
__field(u16, rqid)
|
||||
__field(u16, len)
|
||||
__field(u8, tid)
|
||||
__field(u8, sid)
|
||||
__field(u8, tc)
|
||||
__field(u8, cid)
|
||||
__field(u8, iid)
|
||||
@ -320,14 +365,18 @@ DECLARE_EVENT_CLASS(ssam_command_class,
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->rqid = get_unaligned_le16(&cmd->rqid);
|
||||
__entry->tid = cmd->tid;
|
||||
__entry->sid = cmd->sid;
|
||||
__entry->tc = cmd->tc;
|
||||
__entry->cid = cmd->cid;
|
||||
__entry->iid = cmd->iid;
|
||||
__entry->len = len;
|
||||
),
|
||||
|
||||
TP_printk("rqid=%#06x, tc=%s, cid=%#04x, iid=%#04x, len=%u",
|
||||
TP_printk("rqid=%#06x, tid=%s, sid=%s, tc=%s, cid=%#04x, iid=%#04x, len=%u",
|
||||
__entry->rqid,
|
||||
ssam_show_ssh_tid(__entry->tid),
|
||||
ssam_show_ssh_tid(__entry->sid),
|
||||
ssam_show_ssh_tc(__entry->tc),
|
||||
__entry->cid,
|
||||
__entry->iid,
|
||||
@ -430,6 +479,8 @@ DECLARE_EVENT_CLASS(ssam_request_class,
|
||||
__field(u8, tc)
|
||||
__field(u16, cid)
|
||||
__field(u16, iid)
|
||||
__field(u8, tid)
|
||||
__field(u8, sid)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
@ -439,16 +490,20 @@ DECLARE_EVENT_CLASS(ssam_request_class,
|
||||
__entry->state = READ_ONCE(request->state);
|
||||
__entry->rqid = ssam_trace_get_request_id(p);
|
||||
ssam_trace_ptr_uid(p, __entry->uid);
|
||||
__entry->tid = ssam_trace_get_request_tid(p);
|
||||
__entry->sid = ssam_trace_get_request_sid(p);
|
||||
__entry->tc = ssam_trace_get_request_tc(p);
|
||||
__entry->cid = ssam_trace_get_command_field_u8(p, cid);
|
||||
__entry->iid = ssam_trace_get_command_field_u8(p, iid);
|
||||
),
|
||||
|
||||
TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s",
|
||||
TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tid=%s, sid=%s, tc=%s, cid=%s, iid=%s",
|
||||
__entry->uid,
|
||||
ssam_show_request_id(__entry->rqid),
|
||||
ssam_show_request_type(__entry->state),
|
||||
ssam_show_request_state(__entry->state),
|
||||
ssam_show_ssh_tid(__entry->tid),
|
||||
ssam_show_ssh_tid(__entry->sid),
|
||||
ssam_show_ssh_tc(__entry->tc),
|
||||
ssam_show_generic_u8_field(__entry->cid),
|
||||
ssam_show_generic_u8_field(__entry->iid)
|
||||
@ -474,6 +529,8 @@ DECLARE_EVENT_CLASS(ssam_request_status_class,
|
||||
__field(u8, tc)
|
||||
__field(u16, cid)
|
||||
__field(u16, iid)
|
||||
__field(u8, tid)
|
||||
__field(u8, sid)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
@ -484,16 +541,20 @@ DECLARE_EVENT_CLASS(ssam_request_status_class,
|
||||
__entry->rqid = ssam_trace_get_request_id(p);
|
||||
__entry->status = status;
|
||||
ssam_trace_ptr_uid(p, __entry->uid);
|
||||
__entry->tid = ssam_trace_get_request_tid(p);
|
||||
__entry->sid = ssam_trace_get_request_sid(p);
|
||||
__entry->tc = ssam_trace_get_request_tc(p);
|
||||
__entry->cid = ssam_trace_get_command_field_u8(p, cid);
|
||||
__entry->iid = ssam_trace_get_command_field_u8(p, iid);
|
||||
),
|
||||
|
||||
TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s, status=%d",
|
||||
TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tid=%s, sid=%s, tc=%s, cid=%s, iid=%s, status=%d",
|
||||
__entry->uid,
|
||||
ssam_show_request_id(__entry->rqid),
|
||||
ssam_show_request_type(__entry->state),
|
||||
ssam_show_request_state(__entry->state),
|
||||
ssam_show_ssh_tid(__entry->tid),
|
||||
ssam_show_ssh_tid(__entry->sid),
|
||||
ssam_show_ssh_tc(__entry->tc),
|
||||
ssam_show_generic_u8_field(__entry->cid),
|
||||
ssam_show_generic_u8_field(__entry->iid),
|
||||
|
@ -590,7 +590,7 @@ static acpi_status san_rqst(struct san_data *d, struct gsb_buffer *buffer)
|
||||
return san_rqst_fixup_suspended(d, &rqst, buffer);
|
||||
}
|
||||
|
||||
status = __ssam_retry(ssam_request_sync_onstack, SAN_REQUEST_NUM_TRIES,
|
||||
status = __ssam_retry(ssam_request_do_sync_onstack, SAN_REQUEST_NUM_TRIES,
|
||||
d->ctrl, &rqst, &rsp, SAN_GSB_MAX_RQSX_PAYLOAD);
|
||||
|
||||
if (!status) {
|
||||
|
@ -302,8 +302,8 @@ static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_
|
||||
* theoretical maximum (SSH_COMMAND_MAX_PAYLOAD_SIZE) of the
|
||||
* underlying protocol (note that nothing remotely this size
|
||||
* should ever be allocated in any normal case). This size is
|
||||
* validated later in ssam_request_sync(), for allocation the
|
||||
* bound imposed by u16 should be enough.
|
||||
* validated later in ssam_request_do_sync(), for allocation
|
||||
* the bound imposed by u16 should be enough.
|
||||
*/
|
||||
spec.payload = kzalloc(spec.length, GFP_KERNEL);
|
||||
if (!spec.payload) {
|
||||
@ -342,7 +342,7 @@ static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_
|
||||
}
|
||||
|
||||
/* Perform request. */
|
||||
status = ssam_request_sync(client->cdev->ctrl, &spec, &rsp);
|
||||
status = ssam_request_do_sync(client->cdev->ctrl, &spec, &rsp);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
|
@ -214,7 +214,7 @@ static void ssam_hub_remove(struct ssam_device *sdev)
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x0d,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
@ -292,7 +292,7 @@ static const struct ssam_hub_desc base_hub = {
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_query_state, u8, {
|
||||
.target_category = SSAM_SSH_TC_KIP,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x2c,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
@ -348,8 +348,8 @@ static const struct ssam_hub_desc kip_hub = {
|
||||
/* -- Driver registration. -------------------------------------------------- */
|
||||
|
||||
static const struct ssam_device_id ssam_hub_match[] = {
|
||||
{ SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub },
|
||||
{ SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub },
|
||||
{ SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub },
|
||||
{ SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssam, ssam_hub_match);
|
||||
|
@ -46,7 +46,7 @@ static const struct software_node ssam_node_hub_kip = {
|
||||
|
||||
/* Base device hub (devices attached to Surface Book 3 base). */
|
||||
static const struct software_node ssam_node_hub_base = {
|
||||
.name = "ssam:00:00:02:11:00",
|
||||
.name = "ssam:00:00:01:11:00",
|
||||
.parent = &ssam_node_root,
|
||||
};
|
||||
|
||||
|
@ -247,7 +247,7 @@ static bool ssam_kip_cover_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 s
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_cover_state, u8, {
|
||||
.target_category = SSAM_SSH_TC_KIP,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x1d,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
@ -371,7 +371,7 @@ static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sour
|
||||
int status;
|
||||
|
||||
rqst.target_category = SSAM_SSH_TC_POS;
|
||||
rqst.target_id = 0x01;
|
||||
rqst.target_id = SSAM_SSH_TID_SAM;
|
||||
rqst.command_id = 0x01;
|
||||
rqst.instance_id = 0x00;
|
||||
rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
|
||||
@ -382,7 +382,7 @@ static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sour
|
||||
rsp.length = 0;
|
||||
rsp.pointer = (u8 *)sources;
|
||||
|
||||
status = ssam_retry(ssam_request_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0);
|
||||
status = ssam_retry(ssam_request_do_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@ -430,7 +430,7 @@ static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id)
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_WR(__ssam_pos_get_posture_for_source, __le32, __le32, {
|
||||
.target_category = SSAM_SSH_TC_POS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x02,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
@ -510,8 +510,8 @@ static const struct ssam_tablet_sw_desc ssam_pos_sw_desc = {
|
||||
/* -- Driver registration. -------------------------------------------------- */
|
||||
|
||||
static const struct ssam_device_id ssam_tablet_sw_match[] = {
|
||||
{ SSAM_SDEV(KIP, 0x01, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc },
|
||||
{ SSAM_SDEV(POS, 0x01, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc },
|
||||
{ SSAM_SDEV(KIP, SAM, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc },
|
||||
{ SSAM_SDEV(POS, SAM, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssam, ssam_tablet_sw_match);
|
||||
|
@ -71,63 +71,63 @@ static_assert(sizeof(struct ssam_bas_base_info) == 2);
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x06,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_unlock, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x07,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_request, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x08,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_confirm, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x09,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_heartbeat, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x0a,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_cancel, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x0b,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x0c,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_device_mode, u8, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x0d,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
|
||||
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_latch_status, u8, {
|
||||
.target_category = SSAM_SSH_TC_BAS,
|
||||
.target_id = 0x01,
|
||||
.target_id = SSAM_SSH_TID_SAM,
|
||||
.command_id = 0x11,
|
||||
.instance_id = 0x00,
|
||||
});
|
||||
@ -1214,7 +1214,7 @@ static void surface_dtx_ssam_remove(struct ssam_device *sdev)
|
||||
}
|
||||
|
||||
static const struct ssam_device_id surface_dtx_ssam_match[] = {
|
||||
{ SSAM_SDEV(BAS, 0x01, 0x00, 0x00) },
|
||||
{ SSAM_SDEV(BAS, SAM, 0x00, 0x00) },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssam, surface_dtx_ssam_match);
|
||||
|
@ -101,18 +101,12 @@ static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type
|
||||
param.type = ACPI_TYPE_INTEGER;
|
||||
param.integer.value = value;
|
||||
|
||||
result = acpi_evaluate_dsm(handle, &shps_dsm_guid, SHPS_DSM_REVISION,
|
||||
shps_dsm_fn_for_irq(type), ¶m);
|
||||
|
||||
result = acpi_evaluate_dsm_typed(handle, &shps_dsm_guid, SHPS_DSM_REVISION,
|
||||
shps_dsm_fn_for_irq(type), ¶m, ACPI_TYPE_BUFFER);
|
||||
if (!result) {
|
||||
dev_err(&pdev->dev, "IRQ notification via DSM failed (irq=%d, gpio=%d)\n",
|
||||
type, value);
|
||||
|
||||
} else if (result->type != ACPI_TYPE_BUFFER) {
|
||||
dev_err(&pdev->dev,
|
||||
"IRQ notification via DSM failed: unexpected result type (irq=%d, gpio=%d)\n",
|
||||
type, value);
|
||||
|
||||
} else if (result->buffer.length != 1 || result->buffer.pointer[0] != 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"IRQ notification via DSM failed: unexpected result value (irq=%d, gpio=%d)\n",
|
||||
@ -121,8 +115,7 @@ static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type
|
||||
|
||||
mutex_unlock(&sdev->lock[type]);
|
||||
|
||||
if (result)
|
||||
ACPI_FREE(result);
|
||||
ACPI_FREE(result);
|
||||
}
|
||||
|
||||
static irqreturn_t shps_handle_irq(int irq, void *data)
|
||||
|
@ -169,7 +169,7 @@ static void surface_platform_profile_remove(struct ssam_device *sdev)
|
||||
}
|
||||
|
||||
static const struct ssam_device_id ssam_platform_profile_match[] = {
|
||||
{ SSAM_SDEV(TMP, 0x01, 0x00, 0x01) },
|
||||
{ SSAM_SDEV(TMP, SAM, 0x00, 0x01) },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssam, ssam_platform_profile_match);
|
||||
|
@ -214,7 +214,6 @@ config APPLE_GMUX
|
||||
depends on PNP
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on BACKLIGHT_APPLE=n || BACKLIGHT_APPLE
|
||||
depends on ACPI_VIDEO=n || ACPI_VIDEO
|
||||
help
|
||||
This driver provides support for the gmux device found on many
|
||||
Apple laptops, which controls the display mux for the hybrid
|
||||
|
@ -544,11 +544,6 @@ static int acerhdf_probe(struct platform_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acerhdf_remove(struct platform_device *device)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops acerhdf_pm_ops = {
|
||||
.suspend = acerhdf_suspend,
|
||||
.freeze = acerhdf_suspend,
|
||||
@ -560,7 +555,6 @@ static struct platform_driver acerhdf_driver = {
|
||||
.pm = &acerhdf_pm_ops,
|
||||
},
|
||||
.probe = acerhdf_probe,
|
||||
.remove = acerhdf_remove,
|
||||
};
|
||||
|
||||
/* check hardware */
|
||||
|
@ -43,6 +43,7 @@
|
||||
#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001
|
||||
#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002
|
||||
#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003
|
||||
#define AMD_PMC_STB_DUMMY_PC 0xC6000007
|
||||
|
||||
/* STB S2D(Spill to DRAM) has different message port offset */
|
||||
#define STB_SPILL_TO_DRAM 0xBE
|
||||
@ -104,6 +105,7 @@
|
||||
#define DELAY_MIN_US 2000
|
||||
#define DELAY_MAX_US 3000
|
||||
#define FIFO_SIZE 4096
|
||||
|
||||
enum amd_pmc_def {
|
||||
MSG_TEST = 0x01,
|
||||
MSG_OS_HINT_PCO,
|
||||
@ -114,6 +116,7 @@ enum s2d_arg {
|
||||
S2D_TELEMETRY_SIZE = 0x01,
|
||||
S2D_PHYS_ADDR_LOW,
|
||||
S2D_PHYS_ADDR_HIGH,
|
||||
S2D_NUM_SAMPLES,
|
||||
};
|
||||
|
||||
struct amd_pmc_bit_map {
|
||||
@ -246,13 +249,40 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = {
|
||||
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;
|
||||
u32 *buf, fsize, num_samples, stb_rdptr_offset = 0;
|
||||
int ret;
|
||||
|
||||
/* Write dummy postcode while reading the STB buffer */
|
||||
ret = amd_pmc_write_stb(dev, AMD_PMC_STB_DUMMY_PC);
|
||||
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;
|
||||
|
||||
memcpy_fromio(buf, dev->stb_virt_addr, S2D_TELEMETRY_BYTES_MAX);
|
||||
/* Spill to DRAM num_samples uses separate SMU message port */
|
||||
dev->msg_port = 1;
|
||||
|
||||
/* Get the num_samples to calculate the last push location */
|
||||
ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, STB_SPILL_TO_DRAM, 1);
|
||||
/* 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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Start capturing data from the last push location */
|
||||
if (num_samples > S2D_TELEMETRY_BYTES_MAX) {
|
||||
fsize = S2D_TELEMETRY_BYTES_MAX;
|
||||
stb_rdptr_offset = num_samples - fsize;
|
||||
} else {
|
||||
fsize = num_samples;
|
||||
stb_rdptr_offset = 0;
|
||||
}
|
||||
|
||||
memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize);
|
||||
filp->private_data = buf;
|
||||
|
||||
return 0;
|
||||
@ -560,13 +590,13 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
|
||||
}
|
||||
|
||||
value = amd_pmc_reg_read(dev, response);
|
||||
dev_dbg(dev->dev, "AMD_PMC_REGISTER_RESPONSE:%x\n", value);
|
||||
dev_dbg(dev->dev, "AMD_%s_REGISTER_RESPONSE:%x\n", dev->msg_port ? "S2D" : "PMC", value);
|
||||
|
||||
value = amd_pmc_reg_read(dev, argument);
|
||||
dev_dbg(dev->dev, "AMD_PMC_REGISTER_ARGUMENT:%x\n", value);
|
||||
dev_dbg(dev->dev, "AMD_%s_REGISTER_ARGUMENT:%x\n", dev->msg_port ? "S2D" : "PMC", value);
|
||||
|
||||
value = amd_pmc_reg_read(dev, message);
|
||||
dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value);
|
||||
dev_dbg(dev->dev, "AMD_%s_REGISTER_MESSAGE:%x\n", dev->msg_port ? "S2D" : "PMC", value);
|
||||
}
|
||||
|
||||
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret)
|
||||
|
@ -6,6 +6,7 @@
|
||||
config AMD_PMF
|
||||
tristate "AMD Platform Management Framework"
|
||||
depends on ACPI && PCI
|
||||
depends on POWER_SUPPLY
|
||||
select ACPI_PLATFORM_PROFILE
|
||||
help
|
||||
This driver provides support for the AMD Platform Management Framework.
|
||||
|
@ -192,12 +192,12 @@ config DELL_WMI_DESCRIPTOR
|
||||
config DELL_WMI_DDV
|
||||
tristate "Dell WMI sensors Support"
|
||||
default m
|
||||
depends on ACPI_BATTERY
|
||||
depends on ACPI_WMI
|
||||
depends on ACPI_BATTERY || HWMON
|
||||
help
|
||||
This option adds support for WMI-based sensors like
|
||||
battery temperature sensors found on some Dell notebooks.
|
||||
It also supports reading of the battery ePPID.
|
||||
This option adds support for WMI-based fan and thermal sensors
|
||||
found on some Dell notebooks. It also supports various WMI-based battery
|
||||
extras like reading of the battery temperature and ePPID.
|
||||
|
||||
To compile this drivers as a module, choose M here: the module will
|
||||
be called dell-wmi-ddv.
|
||||
|
@ -67,10 +67,7 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
|
||||
|
||||
retval = 1;
|
||||
|
||||
if (data < 255)
|
||||
byte_data = data;
|
||||
else
|
||||
byte_data = 255;
|
||||
byte_data = min_t(u32, data, 255);
|
||||
|
||||
if (put_user(byte_data, buf))
|
||||
retval = -EFAULT;
|
||||
|
@ -10,28 +10,43 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/device/driver.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#include <acpi/battery.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define DRIVER_NAME "dell-wmi-ddv"
|
||||
|
||||
#define DELL_DDV_SUPPORTED_INTERFACE 2
|
||||
#define DELL_DDV_SUPPORTED_VERSION_MIN 2
|
||||
#define DELL_DDV_SUPPORTED_VERSION_MAX 3
|
||||
#define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608"
|
||||
|
||||
#define DELL_EPPID_LENGTH 20
|
||||
#define DELL_EPPID_EXT_LENGTH 23
|
||||
|
||||
static bool force;
|
||||
module_param_unsafe(force, bool, 0);
|
||||
MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions");
|
||||
|
||||
enum dell_ddv_method {
|
||||
DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01,
|
||||
DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02,
|
||||
@ -49,6 +64,7 @@ enum dell_ddv_method {
|
||||
DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E,
|
||||
DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F,
|
||||
DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10,
|
||||
DELL_DDV_BATTERY_RAW_ANALYTICS_A_BLOCK = 0x11, /* version 3 */
|
||||
|
||||
DELL_DDV_INTERFACE_VERSION = 0x12,
|
||||
|
||||
@ -56,13 +72,63 @@ enum dell_ddv_method {
|
||||
DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22,
|
||||
};
|
||||
|
||||
struct fan_sensor_entry {
|
||||
u8 type;
|
||||
__le16 rpm;
|
||||
} __packed;
|
||||
|
||||
struct thermal_sensor_entry {
|
||||
u8 type;
|
||||
s8 now;
|
||||
s8 min;
|
||||
s8 max;
|
||||
u8 unknown;
|
||||
} __packed;
|
||||
|
||||
struct combined_channel_info {
|
||||
struct hwmon_channel_info info;
|
||||
u32 config[];
|
||||
};
|
||||
|
||||
struct combined_chip_info {
|
||||
struct hwmon_chip_info chip;
|
||||
const struct hwmon_channel_info *info[];
|
||||
};
|
||||
|
||||
struct dell_wmi_ddv_sensors {
|
||||
struct mutex lock; /* protect caching */
|
||||
unsigned long timestamp;
|
||||
union acpi_object *obj;
|
||||
u64 entries;
|
||||
};
|
||||
|
||||
struct dell_wmi_ddv_data {
|
||||
struct acpi_battery_hook hook;
|
||||
struct device_attribute temp_attr;
|
||||
struct device_attribute eppid_attr;
|
||||
struct dell_wmi_ddv_sensors fans;
|
||||
struct dell_wmi_ddv_sensors temps;
|
||||
struct wmi_device *wdev;
|
||||
};
|
||||
|
||||
static const char * const fan_labels[] = {
|
||||
"CPU Fan",
|
||||
"Chassis Motherboard Fan",
|
||||
"Video Fan",
|
||||
"Power Supply Fan",
|
||||
"Chipset Fan",
|
||||
"Memory Fan",
|
||||
"PCI Fan",
|
||||
"HDD Fan",
|
||||
};
|
||||
|
||||
static const char * const fan_dock_labels[] = {
|
||||
"Docking Chassis/Motherboard Fan",
|
||||
"Docking Video Fan",
|
||||
"Docking Power Supply Fan",
|
||||
"Docking Chipset Fan",
|
||||
};
|
||||
|
||||
static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg,
|
||||
union acpi_object **result, acpi_object_type type)
|
||||
{
|
||||
@ -84,7 +150,7 @@ static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method
|
||||
|
||||
if (obj->type != type) {
|
||||
kfree(obj);
|
||||
return -EIO;
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
*result = obj;
|
||||
@ -123,21 +189,27 @@ static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_meth
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (obj->package.count != 2)
|
||||
goto err_free;
|
||||
if (obj->package.count != 2 ||
|
||||
obj->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
obj->package.elements[1].type != ACPI_TYPE_BUFFER) {
|
||||
ret = -ENOMSG;
|
||||
|
||||
if (obj->package.elements[0].type != ACPI_TYPE_INTEGER)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
buffer_size = obj->package.elements[0].integer.value;
|
||||
|
||||
if (obj->package.elements[1].type != ACPI_TYPE_BUFFER)
|
||||
if (!buffer_size) {
|
||||
ret = -ENODATA;
|
||||
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (buffer_size > obj->package.elements[1].buffer.length) {
|
||||
dev_warn(&wdev->dev,
|
||||
FW_WARN "WMI buffer size (%llu) exceeds ACPI buffer size (%d)\n",
|
||||
buffer_size, obj->package.elements[1].buffer.length);
|
||||
ret = -EMSGSIZE;
|
||||
|
||||
goto err_free;
|
||||
}
|
||||
@ -149,7 +221,7 @@ static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_meth
|
||||
err_free:
|
||||
kfree(obj);
|
||||
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method,
|
||||
@ -158,6 +230,410 @@ static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_meth
|
||||
return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Needs to be called with lock held, except during initialization.
|
||||
*/
|
||||
static int dell_wmi_ddv_update_sensors(struct wmi_device *wdev, enum dell_ddv_method method,
|
||||
struct dell_wmi_ddv_sensors *sensors, size_t entry_size)
|
||||
{
|
||||
u64 buffer_size, rem, entries;
|
||||
union acpi_object *obj;
|
||||
u8 *buffer;
|
||||
int ret;
|
||||
|
||||
if (sensors->obj) {
|
||||
if (time_before(jiffies, sensors->timestamp + HZ))
|
||||
return 0;
|
||||
|
||||
kfree(sensors->obj);
|
||||
sensors->obj = NULL;
|
||||
}
|
||||
|
||||
ret = dell_wmi_ddv_query_buffer(wdev, method, 0, &obj);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* buffer format sanity check */
|
||||
buffer_size = obj->package.elements[0].integer.value;
|
||||
buffer = obj->package.elements[1].buffer.pointer;
|
||||
entries = div64_u64_rem(buffer_size, entry_size, &rem);
|
||||
if (rem != 1 || buffer[buffer_size - 1] != 0xff) {
|
||||
ret = -ENOMSG;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (!entries) {
|
||||
ret = -ENODATA;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
sensors->obj = obj;
|
||||
sensors->entries = entries;
|
||||
sensors->timestamp = jiffies;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static umode_t dell_wmi_ddv_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
|
||||
int channel)
|
||||
{
|
||||
return 0444;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_fan_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel,
|
||||
long *val)
|
||||
{
|
||||
struct fan_sensor_entry *entry;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION,
|
||||
&data->fans, sizeof(*entry));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (channel >= data->fans.entries)
|
||||
return -ENXIO;
|
||||
|
||||
entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer;
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
*val = get_unaligned_le16(&entry[channel].rpm);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_temp_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel,
|
||||
long *val)
|
||||
{
|
||||
struct thermal_sensor_entry *entry;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION,
|
||||
&data->temps, sizeof(*entry));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (channel >= data->temps.entries)
|
||||
return -ENXIO;
|
||||
|
||||
entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer;
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
*val = entry[channel].now * 1000;
|
||||
return 0;
|
||||
case hwmon_temp_min:
|
||||
*val = entry[channel].min * 1000;
|
||||
return 0;
|
||||
case hwmon_temp_max:
|
||||
*val = entry[channel].max * 1000;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
int channel, long *val)
|
||||
{
|
||||
struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
mutex_lock(&data->fans.lock);
|
||||
ret = dell_wmi_ddv_fan_read_channel(data, attr, channel, val);
|
||||
mutex_unlock(&data->fans.lock);
|
||||
return ret;
|
||||
case hwmon_temp:
|
||||
mutex_lock(&data->temps.lock);
|
||||
ret = dell_wmi_ddv_temp_read_channel(data, attr, channel, val);
|
||||
mutex_unlock(&data->temps.lock);
|
||||
return ret;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_fan_read_string(struct dell_wmi_ddv_data *data, int channel,
|
||||
const char **str)
|
||||
{
|
||||
struct fan_sensor_entry *entry;
|
||||
int ret;
|
||||
u8 type;
|
||||
|
||||
ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION,
|
||||
&data->fans, sizeof(*entry));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (channel >= data->fans.entries)
|
||||
return -ENXIO;
|
||||
|
||||
entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer;
|
||||
type = entry[channel].type;
|
||||
switch (type) {
|
||||
case 0x00 ... 0x07:
|
||||
*str = fan_labels[type];
|
||||
break;
|
||||
case 0x11 ... 0x14:
|
||||
*str = fan_dock_labels[type - 0x11];
|
||||
break;
|
||||
default:
|
||||
*str = "Unknown Fan";
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_temp_read_string(struct dell_wmi_ddv_data *data, int channel,
|
||||
const char **str)
|
||||
{
|
||||
struct thermal_sensor_entry *entry;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION,
|
||||
&data->temps, sizeof(*entry));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (channel >= data->temps.entries)
|
||||
return -ENXIO;
|
||||
|
||||
entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer;
|
||||
switch (entry[channel].type) {
|
||||
case 0x00:
|
||||
*str = "CPU";
|
||||
break;
|
||||
case 0x11:
|
||||
*str = "Video";
|
||||
break;
|
||||
case 0x22:
|
||||
*str = "Memory"; /* sometimes called DIMM */
|
||||
break;
|
||||
case 0x33:
|
||||
*str = "Other";
|
||||
break;
|
||||
case 0x44:
|
||||
*str = "Ambient"; /* sometimes called SKIN */
|
||||
break;
|
||||
case 0x52:
|
||||
*str = "SODIMM";
|
||||
break;
|
||||
case 0x55:
|
||||
*str = "HDD";
|
||||
break;
|
||||
case 0x62:
|
||||
*str = "SODIMM 2";
|
||||
break;
|
||||
case 0x73:
|
||||
*str = "NB";
|
||||
break;
|
||||
case 0x83:
|
||||
*str = "Charger";
|
||||
break;
|
||||
case 0xbb:
|
||||
*str = "Memory 3";
|
||||
break;
|
||||
default:
|
||||
*str = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
int channel, const char **str)
|
||||
{
|
||||
struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_label:
|
||||
mutex_lock(&data->fans.lock);
|
||||
ret = dell_wmi_ddv_fan_read_string(data, channel, str);
|
||||
mutex_unlock(&data->fans.lock);
|
||||
return ret;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_label:
|
||||
mutex_lock(&data->temps.lock);
|
||||
ret = dell_wmi_ddv_temp_read_string(data, channel, str);
|
||||
mutex_unlock(&data->temps.lock);
|
||||
return ret;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct hwmon_ops dell_wmi_ddv_ops = {
|
||||
.is_visible = dell_wmi_ddv_is_visible,
|
||||
.read = dell_wmi_ddv_read,
|
||||
.read_string = dell_wmi_ddv_read_string,
|
||||
};
|
||||
|
||||
static struct hwmon_channel_info *dell_wmi_ddv_channel_create(struct device *dev, u64 count,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 config)
|
||||
{
|
||||
struct combined_channel_info *cinfo;
|
||||
int i;
|
||||
|
||||
cinfo = devm_kzalloc(dev, struct_size(cinfo, config, count + 1), GFP_KERNEL);
|
||||
if (!cinfo)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cinfo->info.type = type;
|
||||
cinfo->info.config = cinfo->config;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
cinfo->config[i] = config;
|
||||
|
||||
return &cinfo->info;
|
||||
}
|
||||
|
||||
static void dell_wmi_ddv_hwmon_cache_invalidate(struct dell_wmi_ddv_sensors *sensors)
|
||||
{
|
||||
mutex_lock(&sensors->lock);
|
||||
kfree(sensors->obj);
|
||||
sensors->obj = NULL;
|
||||
mutex_unlock(&sensors->lock);
|
||||
}
|
||||
|
||||
static void dell_wmi_ddv_hwmon_cache_destroy(void *data)
|
||||
{
|
||||
struct dell_wmi_ddv_sensors *sensors = data;
|
||||
|
||||
mutex_destroy(&sensors->lock);
|
||||
kfree(sensors->obj);
|
||||
}
|
||||
|
||||
static struct hwmon_channel_info *dell_wmi_ddv_channel_init(struct wmi_device *wdev,
|
||||
enum dell_ddv_method method,
|
||||
struct dell_wmi_ddv_sensors *sensors,
|
||||
size_t entry_size,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 config)
|
||||
{
|
||||
struct hwmon_channel_info *info;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_update_sensors(wdev, method, sensors, entry_size);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
mutex_init(&sensors->lock);
|
||||
|
||||
ret = devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
info = dell_wmi_ddv_channel_create(&wdev->dev, sensors->entries, type, config);
|
||||
if (IS_ERR(info))
|
||||
devm_release_action(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_hwmon_add(struct dell_wmi_ddv_data *data)
|
||||
{
|
||||
struct wmi_device *wdev = data->wdev;
|
||||
struct combined_chip_info *cinfo;
|
||||
struct hwmon_channel_info *info;
|
||||
struct device *hdev;
|
||||
int index = 0;
|
||||
int ret;
|
||||
|
||||
if (!devres_open_group(&wdev->dev, dell_wmi_ddv_hwmon_add, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
cinfo = devm_kzalloc(&wdev->dev, struct_size(cinfo, info, 4), GFP_KERNEL);
|
||||
if (!cinfo) {
|
||||
ret = -ENOMEM;
|
||||
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
cinfo->chip.ops = &dell_wmi_ddv_ops;
|
||||
cinfo->chip.info = cinfo->info;
|
||||
|
||||
info = dell_wmi_ddv_channel_create(&wdev->dev, 1, hwmon_chip, HWMON_C_REGISTER_TZ);
|
||||
if (IS_ERR(info)) {
|
||||
ret = PTR_ERR(info);
|
||||
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
cinfo->info[index] = info;
|
||||
index++;
|
||||
|
||||
info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_FAN_SENSOR_INFORMATION, &data->fans,
|
||||
sizeof(struct fan_sensor_entry), hwmon_fan,
|
||||
(HWMON_F_INPUT | HWMON_F_LABEL));
|
||||
if (!IS_ERR(info)) {
|
||||
cinfo->info[index] = info;
|
||||
index++;
|
||||
}
|
||||
|
||||
info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION, &data->temps,
|
||||
sizeof(struct thermal_sensor_entry), hwmon_temp,
|
||||
(HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
|
||||
HWMON_T_LABEL));
|
||||
if (!IS_ERR(info)) {
|
||||
cinfo->info[index] = info;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index < 2) {
|
||||
ret = -ENODEV;
|
||||
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
hdev = devm_hwmon_device_register_with_info(&wdev->dev, "dell_ddv", data, &cinfo->chip,
|
||||
NULL);
|
||||
if (IS_ERR(hdev)) {
|
||||
ret = PTR_ERR(hdev);
|
||||
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
devres_close_group(&wdev->dev, dell_wmi_ddv_hwmon_add);
|
||||
|
||||
return 0;
|
||||
|
||||
err_release:
|
||||
devres_release_group(&wdev->dev, dell_wmi_ddv_hwmon_add);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index)
|
||||
{
|
||||
const char *uid_str;
|
||||
@ -340,8 +816,13 @@ static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context)
|
||||
return ret;
|
||||
|
||||
dev_dbg(&wdev->dev, "WMI interface version: %d\n", version);
|
||||
if (version != DELL_DDV_SUPPORTED_INTERFACE)
|
||||
return -ENODEV;
|
||||
if (version < DELL_DDV_SUPPORTED_VERSION_MIN || version > DELL_DDV_SUPPORTED_VERSION_MAX) {
|
||||
if (!force)
|
||||
return -ENODEV;
|
||||
|
||||
dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u)\n",
|
||||
version);
|
||||
}
|
||||
|
||||
data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
@ -352,9 +833,34 @@ static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context)
|
||||
|
||||
dell_wmi_ddv_debugfs_init(wdev);
|
||||
|
||||
return dell_wmi_ddv_battery_add(data);
|
||||
if (IS_REACHABLE(CONFIG_ACPI_BATTERY)) {
|
||||
ret = dell_wmi_ddv_battery_add(data);
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
dev_warn(&wdev->dev, "Unable to register ACPI battery hook: %d\n", ret);
|
||||
}
|
||||
|
||||
if (IS_REACHABLE(CONFIG_HWMON)) {
|
||||
ret = dell_wmi_ddv_hwmon_add(data);
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
dev_warn(&wdev->dev, "Unable to register hwmon interface: %d\n", ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_resume(struct device *dev)
|
||||
{
|
||||
struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
|
||||
|
||||
/* Force re-reading of all sensors */
|
||||
dell_wmi_ddv_hwmon_cache_invalidate(&data->fans);
|
||||
dell_wmi_ddv_hwmon_cache_invalidate(&data->temps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(dell_wmi_ddv_dev_pm_ops, NULL, dell_wmi_ddv_resume);
|
||||
|
||||
static const struct wmi_device_id dell_wmi_ddv_id_table[] = {
|
||||
{ DELL_DDV_GUID, NULL },
|
||||
{ }
|
||||
@ -364,6 +870,8 @@ MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table);
|
||||
static struct wmi_driver dell_wmi_ddv_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = pm_sleep_ptr(&dell_wmi_ddv_dev_pm_ops),
|
||||
},
|
||||
.id_table = dell_wmi_ddv_id_table,
|
||||
.probe = dell_wmi_ddv_probe,
|
||||
|
@ -255,7 +255,7 @@ static void attr_name_release(struct kobject *kobj)
|
||||
kfree(kobj);
|
||||
}
|
||||
|
||||
static struct kobj_type attr_name_ktype = {
|
||||
static const struct kobj_type attr_name_ktype = {
|
||||
.release = attr_name_release,
|
||||
.sysfs_ops = &wmi_sysman_kobj_sysfs_ops,
|
||||
};
|
||||
|
@ -217,6 +217,8 @@ static const struct key_entry hp_wmi_keymap[] = {
|
||||
{ KE_KEY, 0x213b, { KEY_INFO } },
|
||||
{ KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } },
|
||||
{ KE_KEY, 0x216a, { KEY_SETUP } },
|
||||
{ KE_IGNORE, 0x21a4, }, /* Win Lock On */
|
||||
{ KE_IGNORE, 0x121a4, }, /* Win Lock Off */
|
||||
{ KE_KEY, 0x21a5, { KEY_PROG2 } }, /* HP Omen Key */
|
||||
{ KE_KEY, 0x21a7, { KEY_FN_ESC } },
|
||||
{ KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } },
|
||||
|
@ -182,6 +182,19 @@ config INTEL_SMARTCONNECT
|
||||
This driver checks to determine whether the device has Intel Smart
|
||||
Connect enabled, and if so disables it.
|
||||
|
||||
config INTEL_TPMI
|
||||
tristate "Intel Topology Aware Register and PM Capsule Interface (TPMI)"
|
||||
depends on INTEL_VSEC
|
||||
depends on X86_64
|
||||
help
|
||||
The Intel Topology Aware Register and PM Capsule Interface (TPMI),
|
||||
provides enumerable MMIO interface for power management features.
|
||||
This driver creates devices, so that other PM feature driver can
|
||||
be loaded for PM specific feature operation.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called intel_vsec_tpmi.
|
||||
|
||||
config INTEL_TURBO_MAX_3
|
||||
bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
|
||||
depends on X86_64 && SCHED_MC_PRIO
|
||||
|
@ -47,6 +47,10 @@ obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o
|
||||
intel_punit_ipc-y := punit_ipc.o
|
||||
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
|
||||
|
||||
# TPMI drivers
|
||||
intel_vsec_tpmi-y := tpmi.o
|
||||
obj-$(CONFIG_INTEL_TPMI) += intel_vsec_tpmi.o
|
||||
|
||||
# Intel Uncore drivers
|
||||
intel-rst-y := rst.o
|
||||
obj-$(CONFIG_INTEL_RST) += intel-rst.o
|
||||
|
@ -131,16 +131,15 @@ static acpi_status sar_get_device_mode(struct platform_device *device)
|
||||
acpi_status status = AE_OK;
|
||||
union acpi_object *out;
|
||||
u32 rev = 0;
|
||||
int value;
|
||||
|
||||
out = acpi_evaluate_dsm(context->handle, &context->guid, rev,
|
||||
COMMAND_ID_DEV_MODE, NULL);
|
||||
if (get_int_value(out, &value)) {
|
||||
out = acpi_evaluate_dsm_typed(context->handle, &context->guid, rev,
|
||||
COMMAND_ID_DEV_MODE, NULL, ACPI_TYPE_INTEGER);
|
||||
if (!out) {
|
||||
dev_err(&device->dev, "DSM cmd:%d Failed to retrieve value\n", COMMAND_ID_DEV_MODE);
|
||||
status = AE_ERROR;
|
||||
goto dev_mode_error;
|
||||
}
|
||||
context->sar_data.device_mode = value;
|
||||
context->sar_data.device_mode = out->integer.value;
|
||||
update_sar_data(context);
|
||||
sysfs_notify(&device->dev.kobj, NULL, SYSFS_DATANAME);
|
||||
|
||||
@ -221,11 +220,11 @@ static void sar_get_data(int reg, struct wwan_sar_context *context)
|
||||
|
||||
req.type = ACPI_TYPE_INTEGER;
|
||||
req.integer.value = reg;
|
||||
out = acpi_evaluate_dsm(context->handle, &context->guid, rev,
|
||||
COMMAND_ID_CONFIG_TABLE, &req);
|
||||
out = acpi_evaluate_dsm_typed(context->handle, &context->guid, rev,
|
||||
COMMAND_ID_CONFIG_TABLE, &req, ACPI_TYPE_PACKAGE);
|
||||
if (!out)
|
||||
return;
|
||||
if (out->type == ACPI_TYPE_PACKAGE && out->package.count >= 3 &&
|
||||
if (out->package.count >= 3 &&
|
||||
out->package.elements[0].type == ACPI_TYPE_INTEGER &&
|
||||
out->package.elements[1].type == ACPI_TYPE_INTEGER &&
|
||||
out->package.elements[2].type == ACPI_TYPE_PACKAGE &&
|
||||
|
@ -4,6 +4,7 @@ config INTEL_SKL_INT3472
|
||||
depends on COMMON_CLK
|
||||
depends on I2C
|
||||
depends on GPIOLIB
|
||||
depends on LEDS_CLASS
|
||||
depends on REGULATOR
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
|
@ -1,4 +1,4 @@
|
||||
obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \
|
||||
intel_skl_int3472_tps68470.o
|
||||
intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o common.o
|
||||
intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o common.o
|
||||
intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o common.o
|
||||
|
@ -23,8 +23,6 @@ static int skl_int3472_clk_prepare(struct clk_hw *hw)
|
||||
struct int3472_gpio_clock *clk = to_int3472_clk(hw);
|
||||
|
||||
gpiod_set_value_cansleep(clk->ena_gpio, 1);
|
||||
gpiod_set_value_cansleep(clk->led_gpio, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -33,7 +31,6 @@ static void skl_int3472_clk_unprepare(struct clk_hw *hw)
|
||||
struct int3472_gpio_clock *clk = to_int3472_clk(hw);
|
||||
|
||||
gpiod_set_value_cansleep(clk->ena_gpio, 0);
|
||||
gpiod_set_value_cansleep(clk->led_gpio, 0);
|
||||
}
|
||||
|
||||
static int skl_int3472_clk_enable(struct clk_hw *hw)
|
||||
@ -89,18 +86,37 @@ static const struct clk_ops skl_int3472_clock_ops = {
|
||||
.recalc_rate = skl_int3472_clk_recalc_rate,
|
||||
};
|
||||
|
||||
int skl_int3472_register_clock(struct int3472_discrete_device *int3472)
|
||||
int skl_int3472_register_clock(struct int3472_discrete_device *int3472,
|
||||
struct acpi_resource_gpio *agpio, u32 polarity)
|
||||
{
|
||||
char *path = agpio->resource_source.string_ptr;
|
||||
struct clk_init_data init = {
|
||||
.ops = &skl_int3472_clock_ops,
|
||||
.flags = CLK_GET_RATE_NOCACHE,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (int3472->clock.cl)
|
||||
return -EBUSY;
|
||||
|
||||
int3472->clock.ena_gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
|
||||
"int3472,clk-enable");
|
||||
if (IS_ERR(int3472->clock.ena_gpio))
|
||||
return dev_err_probe(int3472->dev, PTR_ERR(int3472->clock.ena_gpio),
|
||||
"getting clk-enable GPIO\n");
|
||||
|
||||
if (polarity == GPIO_ACTIVE_LOW)
|
||||
gpiod_toggle_active_low(int3472->clock.ena_gpio);
|
||||
|
||||
/* Ensure the pin is in output mode and non-active state */
|
||||
gpiod_direction_output(int3472->clock.ena_gpio, 0);
|
||||
|
||||
init.name = kasprintf(GFP_KERNEL, "%s-clk",
|
||||
acpi_dev_name(int3472->adev));
|
||||
if (!init.name)
|
||||
return -ENOMEM;
|
||||
if (!init.name) {
|
||||
ret = -ENOMEM;
|
||||
goto out_put_gpio;
|
||||
}
|
||||
|
||||
int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472);
|
||||
|
||||
@ -126,14 +142,20 @@ err_unregister_clk:
|
||||
clk_unregister(int3472->clock.clk);
|
||||
out_free_init_name:
|
||||
kfree(init.name);
|
||||
out_put_gpio:
|
||||
gpiod_put(int3472->clock.ena_gpio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472)
|
||||
{
|
||||
if (!int3472->clock.cl)
|
||||
return;
|
||||
|
||||
clkdev_drop(int3472->clock.cl);
|
||||
clk_unregister(int3472->clock.clk);
|
||||
gpiod_put(int3472->clock.ena_gpio);
|
||||
}
|
||||
|
||||
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/types.h>
|
||||
@ -28,6 +29,8 @@
|
||||
#define GPIO_REGULATOR_NAME_LENGTH 21
|
||||
#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9
|
||||
|
||||
#define INT3472_LED_MAX_NAME_LEN 32
|
||||
|
||||
#define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET 86
|
||||
|
||||
#define INT3472_REGULATOR(_name, _supply, _ops) \
|
||||
@ -96,10 +99,16 @@ struct int3472_discrete_device {
|
||||
struct clk_hw clk_hw;
|
||||
struct clk_lookup *cl;
|
||||
struct gpio_desc *ena_gpio;
|
||||
struct gpio_desc *led_gpio;
|
||||
u32 frequency;
|
||||
} clock;
|
||||
|
||||
struct int3472_pled {
|
||||
struct led_classdev classdev;
|
||||
struct led_lookup_data lookup;
|
||||
char name[INT3472_LED_MAX_NAME_LEN];
|
||||
struct gpio_desc *gpio;
|
||||
} pled;
|
||||
|
||||
unsigned int ngpios; /* how many GPIOs have we seen */
|
||||
unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
|
||||
struct gpiod_lookup_table gpios;
|
||||
@ -112,11 +121,16 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev,
|
||||
struct acpi_device **sensor_adev_ret,
|
||||
const char **name_ret);
|
||||
|
||||
int skl_int3472_register_clock(struct int3472_discrete_device *int3472);
|
||||
int skl_int3472_register_clock(struct int3472_discrete_device *int3472,
|
||||
struct acpi_resource_gpio *agpio, u32 polarity);
|
||||
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
|
||||
|
||||
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
|
||||
struct acpi_resource_gpio *agpio);
|
||||
void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
|
||||
|
||||
int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
|
||||
struct acpi_resource_gpio *agpio, u32 polarity);
|
||||
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472);
|
||||
|
||||
#endif
|
||||
|
@ -2,8 +2,6 @@
|
||||
/* Author: Dan Scally <djrscally@gmail.com> */
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
@ -80,14 +78,6 @@ skl_int3472_get_sensor_module_config(struct int3472_discrete_device *int3472)
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
if (obj->string.type != ACPI_TYPE_STRING) {
|
||||
dev_err(int3472->dev,
|
||||
"Sensor _DSM returned a non-string value\n");
|
||||
|
||||
ACPI_FREE(obj);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(int3472_sensor_configs); i++) {
|
||||
if (!strcmp(int3472_sensor_configs[i].sensor_module_name,
|
||||
obj->string.pointer))
|
||||
@ -154,38 +144,34 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
|
||||
struct acpi_resource_gpio *agpio, u8 type)
|
||||
static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity)
|
||||
{
|
||||
char *path = agpio->resource_source.string_ptr;
|
||||
u16 pin = agpio->pin_table[0];
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
switch (type) {
|
||||
case INT3472_GPIO_TYPE_RESET:
|
||||
*func = "reset";
|
||||
*polarity = GPIO_ACTIVE_LOW;
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_POWERDOWN:
|
||||
*func = "powerdown";
|
||||
*polarity = GPIO_ACTIVE_LOW;
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_CLK_ENABLE:
|
||||
gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable");
|
||||
if (IS_ERR(gpio))
|
||||
return (PTR_ERR(gpio));
|
||||
|
||||
int3472->clock.ena_gpio = gpio;
|
||||
/* Ensure the pin is in output mode and non-active state */
|
||||
gpiod_direction_output(int3472->clock.ena_gpio, 0);
|
||||
*func = "clk-enable";
|
||||
*polarity = GPIO_ACTIVE_HIGH;
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_PRIVACY_LED:
|
||||
gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led");
|
||||
if (IS_ERR(gpio))
|
||||
return (PTR_ERR(gpio));
|
||||
|
||||
int3472->clock.led_gpio = gpio;
|
||||
/* Ensure the pin is in output mode and non-active state */
|
||||
gpiod_direction_output(int3472->clock.led_gpio, 0);
|
||||
*func = "privacy-led";
|
||||
*polarity = GPIO_ACTIVE_HIGH;
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_POWER_ENABLE:
|
||||
*func = "power-enable";
|
||||
*polarity = GPIO_ACTIVE_HIGH;
|
||||
break;
|
||||
default:
|
||||
dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type);
|
||||
*func = "unknown";
|
||||
*polarity = GPIO_ACTIVE_HIGH;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,9 +212,11 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
|
||||
struct int3472_discrete_device *int3472 = data;
|
||||
struct acpi_resource_gpio *agpio;
|
||||
union acpi_object *obj;
|
||||
u8 active_value, type;
|
||||
const char *err_msg;
|
||||
const char *func;
|
||||
u32 polarity;
|
||||
int ret;
|
||||
u8 type;
|
||||
|
||||
if (!acpi_gpio_get_io_resource(ares, &agpio))
|
||||
return 1;
|
||||
@ -250,26 +238,35 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
|
||||
|
||||
type = obj->integer.value & 0xff;
|
||||
|
||||
int3472_get_func_and_polarity(type, &func, &polarity);
|
||||
|
||||
/* If bits 31-24 of the _DSM entry are all 0 then the signal is inverted */
|
||||
active_value = obj->integer.value >> 24;
|
||||
if (!active_value)
|
||||
polarity ^= GPIO_ACTIVE_LOW;
|
||||
|
||||
dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", func,
|
||||
agpio->resource_source.string_ptr, agpio->pin_table[0],
|
||||
(polarity == GPIO_ACTIVE_HIGH) ? "high" : "low");
|
||||
|
||||
switch (type) {
|
||||
case INT3472_GPIO_TYPE_RESET:
|
||||
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "reset",
|
||||
GPIO_ACTIVE_LOW);
|
||||
if (ret)
|
||||
err_msg = "Failed to map reset pin to sensor\n";
|
||||
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_POWERDOWN:
|
||||
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "powerdown",
|
||||
GPIO_ACTIVE_LOW);
|
||||
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, func, polarity);
|
||||
if (ret)
|
||||
err_msg = "Failed to map powerdown pin to sensor\n";
|
||||
err_msg = "Failed to map GPIO pin to sensor\n";
|
||||
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_CLK_ENABLE:
|
||||
case INT3472_GPIO_TYPE_PRIVACY_LED:
|
||||
ret = skl_int3472_map_gpio_to_clk(int3472, agpio, type);
|
||||
ret = skl_int3472_register_clock(int3472, agpio, polarity);
|
||||
if (ret)
|
||||
err_msg = "Failed to map GPIO to clock\n";
|
||||
err_msg = "Failed to register clock\n";
|
||||
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_PRIVACY_LED:
|
||||
ret = skl_int3472_register_pled(int3472, agpio, polarity);
|
||||
if (ret)
|
||||
err_msg = "Failed to register LED\n";
|
||||
|
||||
break;
|
||||
case INT3472_GPIO_TYPE_POWER_ENABLE:
|
||||
@ -314,21 +311,6 @@ static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472)
|
||||
|
||||
acpi_dev_free_resource_list(&resource_list);
|
||||
|
||||
/*
|
||||
* If we find no clock enable GPIO pin then the privacy LED won't work.
|
||||
* We've never seen that situation, but it's possible. Warn the user so
|
||||
* it's clear what's happened.
|
||||
*/
|
||||
if (int3472->clock.ena_gpio) {
|
||||
ret = skl_int3472_register_clock(int3472);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
if (int3472->clock.led_gpio)
|
||||
dev_warn(int3472->dev,
|
||||
"No clk GPIO. The privacy LED won't work\n");
|
||||
}
|
||||
|
||||
int3472->gpios.dev_id = int3472->sensor_name;
|
||||
gpiod_add_lookup_table(&int3472->gpios);
|
||||
|
||||
@ -341,12 +323,8 @@ static int skl_int3472_discrete_remove(struct platform_device *pdev)
|
||||
|
||||
gpiod_remove_lookup_table(&int3472->gpios);
|
||||
|
||||
if (int3472->clock.cl)
|
||||
skl_int3472_unregister_clock(int3472);
|
||||
|
||||
gpiod_put(int3472->clock.ena_gpio);
|
||||
gpiod_put(int3472->clock.led_gpio);
|
||||
|
||||
skl_int3472_unregister_clock(int3472);
|
||||
skl_int3472_unregister_pled(int3472);
|
||||
skl_int3472_unregister_regulator(int3472);
|
||||
|
||||
return 0;
|
||||
|
75
drivers/platform/x86/intel/int3472/led.c
Normal file
75
drivers/platform/x86/intel/int3472/led.c
Normal file
@ -0,0 +1,75 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Author: Hans de Goede <hdegoede@redhat.com> */
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/leds.h>
|
||||
#include "common.h"
|
||||
|
||||
static int int3472_pled_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct int3472_discrete_device *int3472 =
|
||||
container_of(led_cdev, struct int3472_discrete_device, pled.classdev);
|
||||
|
||||
gpiod_set_value_cansleep(int3472->pled.gpio, brightness);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
|
||||
struct acpi_resource_gpio *agpio, u32 polarity)
|
||||
{
|
||||
char *p, *path = agpio->resource_source.string_ptr;
|
||||
int ret;
|
||||
|
||||
if (int3472->pled.classdev.dev)
|
||||
return -EBUSY;
|
||||
|
||||
int3472->pled.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
|
||||
"int3472,privacy-led");
|
||||
if (IS_ERR(int3472->pled.gpio))
|
||||
return dev_err_probe(int3472->dev, PTR_ERR(int3472->pled.gpio),
|
||||
"getting privacy LED GPIO\n");
|
||||
|
||||
if (polarity == GPIO_ACTIVE_LOW)
|
||||
gpiod_toggle_active_low(int3472->pled.gpio);
|
||||
|
||||
/* Ensure the pin is in output mode and non-active state */
|
||||
gpiod_direction_output(int3472->pled.gpio, 0);
|
||||
|
||||
/* Generate the name, replacing the ':' in the ACPI devname with '_' */
|
||||
snprintf(int3472->pled.name, sizeof(int3472->pled.name),
|
||||
"%s::privacy_led", acpi_dev_name(int3472->sensor));
|
||||
p = strchr(int3472->pled.name, ':');
|
||||
if (p)
|
||||
*p = '_';
|
||||
|
||||
int3472->pled.classdev.name = int3472->pled.name;
|
||||
int3472->pled.classdev.max_brightness = 1;
|
||||
int3472->pled.classdev.brightness_set_blocking = int3472_pled_set;
|
||||
|
||||
ret = led_classdev_register(int3472->dev, &int3472->pled.classdev);
|
||||
if (ret)
|
||||
goto err_free_gpio;
|
||||
|
||||
int3472->pled.lookup.provider = int3472->pled.name;
|
||||
int3472->pled.lookup.dev_id = int3472->sensor_name;
|
||||
int3472->pled.lookup.con_id = "privacy-led";
|
||||
led_add_lookup(&int3472->pled.lookup);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_gpio:
|
||||
gpiod_put(int3472->pled.gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(int3472->pled.classdev.dev))
|
||||
return;
|
||||
|
||||
led_remove_lookup(&int3472->pled.lookup);
|
||||
led_classdev_unregister(&int3472->pled.classdev);
|
||||
gpiod_put(int3472->pled.gpio);
|
||||
}
|
@ -266,17 +266,11 @@ static int oaktrail_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oaktrail_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver oaktrail_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
.probe = oaktrail_probe,
|
||||
.remove = oaktrail_remove,
|
||||
};
|
||||
|
||||
static int dmi_check_cb(const struct dmi_system_id *id)
|
||||
|
@ -221,9 +221,9 @@ void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
|
||||
|
||||
guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
|
||||
|
||||
out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
|
||||
ACPI_GET_LOW_MODE_REGISTERS, NULL);
|
||||
if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
|
||||
out_obj = acpi_evaluate_dsm_typed(adev->handle, &s0ix_dsm_guid, 0,
|
||||
ACPI_GET_LOW_MODE_REGISTERS, NULL, ACPI_TYPE_BUFFER);
|
||||
if (out_obj) {
|
||||
u32 size = out_obj->buffer.length;
|
||||
|
||||
if (size != lpm_size) {
|
||||
|
@ -302,11 +302,6 @@ static int intel_punit_ipc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_punit_ipc_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id punit_ipc_acpi_ids[] = {
|
||||
{ "INT34D4", 0 },
|
||||
{ }
|
||||
@ -315,7 +310,6 @@ MODULE_DEVICE_TABLE(acpi, punit_ipc_acpi_ids);
|
||||
|
||||
static struct platform_driver intel_punit_ipc_driver = {
|
||||
.probe = intel_punit_ipc_probe,
|
||||
.remove = intel_punit_ipc_remove,
|
||||
.driver = {
|
||||
.name = "intel_punit_ipc",
|
||||
.acpi_match_table = punit_ipc_acpi_ids,
|
||||
|
415
drivers/platform/x86/intel/tpmi.c
Normal file
415
drivers/platform/x86/intel/tpmi.c
Normal file
@ -0,0 +1,415 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* intel-tpmi : Driver to enumerate TPMI features and create devices
|
||||
*
|
||||
* Copyright (c) 2023, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* The TPMI (Topology Aware Register and PM Capsule Interface) provides a
|
||||
* flexible, extendable and PCIe enumerable MMIO interface for PM features.
|
||||
*
|
||||
* For example Intel RAPL (Running Average Power Limit) provides a MMIO
|
||||
* interface using TPMI. This has advantage over traditional MSR
|
||||
* (Model Specific Register) interface, where a thread needs to be scheduled
|
||||
* on the target CPU to read or write. Also the RAPL features vary between
|
||||
* CPU models, and hence lot of model specific code. Here TPMI provides an
|
||||
* architectural interface by providing hierarchical tables and fields,
|
||||
* which will not need any model specific implementation.
|
||||
*
|
||||
* The TPMI interface uses a PCI VSEC structure to expose the location of
|
||||
* MMIO region.
|
||||
*
|
||||
* This VSEC structure is present in the PCI configuration space of the
|
||||
* Intel Out-of-Band (OOB) device, which is handled by the Intel VSEC
|
||||
* driver. The Intel VSEC driver parses VSEC structures present in the PCI
|
||||
* configuration space of the given device and creates an auxiliary device
|
||||
* object for each of them. In particular, it creates an auxiliary device
|
||||
* object representing TPMI that can be bound by an auxiliary driver.
|
||||
*
|
||||
* This TPMI driver will bind to the TPMI auxiliary device object created
|
||||
* by the Intel VSEC driver.
|
||||
*
|
||||
* The TPMI specification defines a PFS (PM Feature Structure) table.
|
||||
* This table is present in the TPMI MMIO region. The starting address
|
||||
* of PFS is derived from the tBIR (Bar Indicator Register) and "Address"
|
||||
* field from the VSEC header.
|
||||
*
|
||||
* Each TPMI PM feature has one entry in the PFS with a unique TPMI
|
||||
* ID and its access details. The TPMI driver creates device nodes
|
||||
* for the supported PM features.
|
||||
*
|
||||
* The names of the devices created by the TPMI driver start with the
|
||||
* "intel_vsec.tpmi-" prefix which is followed by a specific name of the
|
||||
* given PM feature (for example, "intel_vsec.tpmi-rapl.0").
|
||||
*
|
||||
* The device nodes are create by using interface "intel_vsec_add_aux()"
|
||||
* provided by the Intel VSEC driver.
|
||||
*/
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/intel_tpmi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "vsec.h"
|
||||
|
||||
/**
|
||||
* struct intel_tpmi_pfs_entry - TPMI PM Feature Structure (PFS) entry
|
||||
* @tpmi_id: TPMI feature identifier (what the feature is and its data format).
|
||||
* @num_entries: Number of feature interface instances present in the PFS.
|
||||
* This represents the maximum number of Power domains in the SoC.
|
||||
* @entry_size: Interface instance entry size in 32-bit words.
|
||||
* @cap_offset: Offset from the PM_Features base address to the base of the PM VSEC
|
||||
* register bank in KB.
|
||||
* @attribute: Feature attribute: 0=BIOS. 1=OS. 2-3=Reserved.
|
||||
* @reserved: Bits for use in the future.
|
||||
*
|
||||
* Represents one TPMI feature entry data in the PFS retrieved as is
|
||||
* from the hardware.
|
||||
*/
|
||||
struct intel_tpmi_pfs_entry {
|
||||
u64 tpmi_id:8;
|
||||
u64 num_entries:8;
|
||||
u64 entry_size:16;
|
||||
u64 cap_offset:16;
|
||||
u64 attribute:2;
|
||||
u64 reserved:14;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct intel_tpmi_pm_feature - TPMI PM Feature information for a TPMI ID
|
||||
* @pfs_header: PFS header retireved from the hardware.
|
||||
* @vsec_offset: Starting MMIO address for this feature in bytes. Essentially
|
||||
* this offset = "Address" from VSEC header + PFS Capability
|
||||
* offset for this feature entry.
|
||||
*
|
||||
* Represents TPMI instance information for one TPMI ID.
|
||||
*/
|
||||
struct intel_tpmi_pm_feature {
|
||||
struct intel_tpmi_pfs_entry pfs_header;
|
||||
unsigned int vsec_offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct intel_tpmi_info - TPMI information for all IDs in an instance
|
||||
* @tpmi_features: Pointer to a list of TPMI feature instances
|
||||
* @vsec_dev: Pointer to intel_vsec_device structure for this TPMI device
|
||||
* @feature_count: Number of TPMI of TPMI instances pointed by tpmi_features
|
||||
* @pfs_start: Start of PFS offset for the TPMI instances in this device
|
||||
* @plat_info: Stores platform info which can be used by the client drivers
|
||||
*
|
||||
* Stores the information for all TPMI devices enumerated from a single PCI device.
|
||||
*/
|
||||
struct intel_tpmi_info {
|
||||
struct intel_tpmi_pm_feature *tpmi_features;
|
||||
struct intel_vsec_device *vsec_dev;
|
||||
int feature_count;
|
||||
u64 pfs_start;
|
||||
struct intel_tpmi_plat_info plat_info;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tpmi_info_header - CPU package ID to PCI device mapping information
|
||||
* @fn: PCI function number
|
||||
* @dev: PCI device number
|
||||
* @bus: PCI bus number
|
||||
* @pkg: CPU Package id
|
||||
* @reserved: Reserved for future use
|
||||
* @lock: When set to 1 the register is locked and becomes read-only
|
||||
* until next reset. Not for use by the OS driver.
|
||||
*
|
||||
* The structure to read hardware provided mapping information.
|
||||
*/
|
||||
struct tpmi_info_header {
|
||||
u64 fn:3;
|
||||
u64 dev:5;
|
||||
u64 bus:8;
|
||||
u64 pkg:8;
|
||||
u64 reserved:39;
|
||||
u64 lock:1;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* List of supported TMPI IDs.
|
||||
* Some TMPI IDs are not used by Linux, so the numbers are not consecutive.
|
||||
*/
|
||||
enum intel_tpmi_id {
|
||||
TPMI_ID_RAPL = 0, /* Running Average Power Limit */
|
||||
TPMI_ID_PEM = 1, /* Power and Perf excursion Monitor */
|
||||
TPMI_ID_UNCORE = 2, /* Uncore Frequency Scaling */
|
||||
TPMI_ID_SST = 5, /* Speed Select Technology */
|
||||
TPMI_INFO_ID = 0x81, /* Special ID for PCI BDF and Package ID information */
|
||||
};
|
||||
|
||||
/* Used during auxbus device creation */
|
||||
static DEFINE_IDA(intel_vsec_tpmi_ida);
|
||||
|
||||
struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev)
|
||||
{
|
||||
struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
|
||||
|
||||
return vsec_dev->priv_data;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(tpmi_get_platform_data, INTEL_TPMI);
|
||||
|
||||
int tpmi_get_resource_count(struct auxiliary_device *auxdev)
|
||||
{
|
||||
struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
|
||||
|
||||
if (vsec_dev)
|
||||
return vsec_dev->num_resources;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_count, INTEL_TPMI);
|
||||
|
||||
struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int index)
|
||||
{
|
||||
struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
|
||||
|
||||
if (vsec_dev && index < vsec_dev->num_resources)
|
||||
return &vsec_dev->resource[index];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
|
||||
|
||||
static const char *intel_tpmi_name(enum intel_tpmi_id id)
|
||||
{
|
||||
switch (id) {
|
||||
case TPMI_ID_RAPL:
|
||||
return "rapl";
|
||||
case TPMI_ID_PEM:
|
||||
return "pem";
|
||||
case TPMI_ID_UNCORE:
|
||||
return "uncore";
|
||||
case TPMI_ID_SST:
|
||||
return "sst";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* String Length for tpmi-"feature_name(upto 8 bytes)" */
|
||||
#define TPMI_FEATURE_NAME_LEN 14
|
||||
|
||||
static int tpmi_create_device(struct intel_tpmi_info *tpmi_info,
|
||||
struct intel_tpmi_pm_feature *pfs,
|
||||
u64 pfs_start)
|
||||
{
|
||||
struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev;
|
||||
char feature_id_name[TPMI_FEATURE_NAME_LEN];
|
||||
struct intel_vsec_device *feature_vsec_dev;
|
||||
struct resource *res, *tmp;
|
||||
const char *name;
|
||||
int ret, i;
|
||||
|
||||
name = intel_tpmi_name(pfs->pfs_header.tpmi_id);
|
||||
if (!name)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
feature_vsec_dev = kzalloc(sizeof(*feature_vsec_dev), GFP_KERNEL);
|
||||
if (!feature_vsec_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = kcalloc(pfs->pfs_header.num_entries, sizeof(*res), GFP_KERNEL);
|
||||
if (!res) {
|
||||
ret = -ENOMEM;
|
||||
goto free_vsec;
|
||||
}
|
||||
|
||||
snprintf(feature_id_name, sizeof(feature_id_name), "tpmi-%s", name);
|
||||
|
||||
for (i = 0, tmp = res; i < pfs->pfs_header.num_entries; i++, tmp++) {
|
||||
u64 entry_size_bytes = pfs->pfs_header.entry_size * 4;
|
||||
|
||||
tmp->start = pfs->vsec_offset + entry_size_bytes * i;
|
||||
tmp->end = tmp->start + entry_size_bytes - 1;
|
||||
tmp->flags = IORESOURCE_MEM;
|
||||
}
|
||||
|
||||
feature_vsec_dev->pcidev = vsec_dev->pcidev;
|
||||
feature_vsec_dev->resource = res;
|
||||
feature_vsec_dev->num_resources = pfs->pfs_header.num_entries;
|
||||
feature_vsec_dev->priv_data = &tpmi_info->plat_info;
|
||||
feature_vsec_dev->priv_data_size = sizeof(tpmi_info->plat_info);
|
||||
feature_vsec_dev->ida = &intel_vsec_tpmi_ida;
|
||||
|
||||
/*
|
||||
* intel_vsec_add_aux() is resource managed, no explicit
|
||||
* delete is required on error or on module unload.
|
||||
*/
|
||||
ret = intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev,
|
||||
feature_vsec_dev, feature_id_name);
|
||||
if (ret)
|
||||
goto free_res;
|
||||
|
||||
return 0;
|
||||
|
||||
free_res:
|
||||
kfree(res);
|
||||
free_vsec:
|
||||
kfree(feature_vsec_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tpmi_create_devices(struct intel_tpmi_info *tpmi_info)
|
||||
{
|
||||
struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < vsec_dev->num_resources; i++) {
|
||||
ret = tpmi_create_device(tpmi_info, &tpmi_info->tpmi_features[i],
|
||||
tpmi_info->pfs_start);
|
||||
/*
|
||||
* Fail, if the supported features fails to create device,
|
||||
* otherwise, continue. Even if one device failed to create,
|
||||
* fail the loading of driver. Since intel_vsec_add_aux()
|
||||
* is resource managed, no clean up is required for the
|
||||
* successfully created devices.
|
||||
*/
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TPMI_INFO_BUS_INFO_OFFSET 0x08
|
||||
|
||||
static int tpmi_process_info(struct intel_tpmi_info *tpmi_info,
|
||||
struct intel_tpmi_pm_feature *pfs)
|
||||
{
|
||||
struct tpmi_info_header header;
|
||||
void __iomem *info_mem;
|
||||
|
||||
info_mem = ioremap(pfs->vsec_offset + TPMI_INFO_BUS_INFO_OFFSET,
|
||||
pfs->pfs_header.entry_size * 4 - TPMI_INFO_BUS_INFO_OFFSET);
|
||||
if (!info_mem)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_fromio(&header, info_mem, sizeof(header));
|
||||
|
||||
tpmi_info->plat_info.package_id = header.pkg;
|
||||
tpmi_info->plat_info.bus_number = header.bus;
|
||||
tpmi_info->plat_info.device_number = header.dev;
|
||||
tpmi_info->plat_info.function_number = header.fn;
|
||||
|
||||
iounmap(info_mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, int size)
|
||||
{
|
||||
void __iomem *pfs_mem;
|
||||
|
||||
pfs_mem = ioremap(start, size);
|
||||
if (!pfs_mem)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_fromio(&pfs->pfs_header, pfs_mem, sizeof(pfs->pfs_header));
|
||||
|
||||
iounmap(pfs_mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
|
||||
{
|
||||
struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
|
||||
struct pci_dev *pci_dev = vsec_dev->pcidev;
|
||||
struct intel_tpmi_info *tpmi_info;
|
||||
u64 pfs_start = 0;
|
||||
int i;
|
||||
|
||||
tpmi_info = devm_kzalloc(&auxdev->dev, sizeof(*tpmi_info), GFP_KERNEL);
|
||||
if (!tpmi_info)
|
||||
return -ENOMEM;
|
||||
|
||||
tpmi_info->vsec_dev = vsec_dev;
|
||||
tpmi_info->feature_count = vsec_dev->num_resources;
|
||||
tpmi_info->plat_info.bus_number = pci_dev->bus->number;
|
||||
|
||||
tpmi_info->tpmi_features = devm_kcalloc(&auxdev->dev, vsec_dev->num_resources,
|
||||
sizeof(*tpmi_info->tpmi_features),
|
||||
GFP_KERNEL);
|
||||
if (!tpmi_info->tpmi_features)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < vsec_dev->num_resources; i++) {
|
||||
struct intel_tpmi_pm_feature *pfs;
|
||||
struct resource *res;
|
||||
u64 res_start;
|
||||
int size, ret;
|
||||
|
||||
pfs = &tpmi_info->tpmi_features[i];
|
||||
|
||||
res = &vsec_dev->resource[i];
|
||||
if (!res)
|
||||
continue;
|
||||
|
||||
res_start = res->start;
|
||||
size = resource_size(res);
|
||||
if (size < 0)
|
||||
continue;
|
||||
|
||||
ret = tpmi_fetch_pfs_header(pfs, res_start, size);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
if (!pfs_start)
|
||||
pfs_start = res_start;
|
||||
|
||||
pfs->pfs_header.cap_offset *= 1024;
|
||||
|
||||
pfs->vsec_offset = pfs_start + pfs->pfs_header.cap_offset;
|
||||
|
||||
/*
|
||||
* Process TPMI_INFO to get PCI device to CPU package ID.
|
||||
* Device nodes for TPMI features are not created in this
|
||||
* for loop. So, the mapping information will be available
|
||||
* when actual device nodes created outside this
|
||||
* loop via tpmi_create_devices().
|
||||
*/
|
||||
if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID)
|
||||
tpmi_process_info(tpmi_info, pfs);
|
||||
}
|
||||
|
||||
tpmi_info->pfs_start = pfs_start;
|
||||
|
||||
auxiliary_set_drvdata(auxdev, tpmi_info);
|
||||
|
||||
return tpmi_create_devices(tpmi_info);
|
||||
}
|
||||
|
||||
static int tpmi_probe(struct auxiliary_device *auxdev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
return intel_vsec_tpmi_init(auxdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove callback is not needed currently as there is no
|
||||
* cleanup required. All memory allocs are device managed. All
|
||||
* devices created by this modules are also device managed.
|
||||
*/
|
||||
|
||||
static const struct auxiliary_device_id tpmi_id_table[] = {
|
||||
{ .name = "intel_vsec.tpmi" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(auxiliary, tpmi_id_table);
|
||||
|
||||
static struct auxiliary_driver tpmi_aux_driver = {
|
||||
.id_table = tpmi_id_table,
|
||||
.probe = tpmi_probe,
|
||||
};
|
||||
|
||||
module_auxiliary_driver(tpmi_aux_driver);
|
||||
|
||||
MODULE_IMPORT_NS(INTEL_VSEC);
|
||||
MODULE_DESCRIPTION("Intel TPMI enumeration module");
|
||||
MODULE_LICENSE("GPL");
|
@ -64,6 +64,7 @@ enum intel_vsec_id {
|
||||
VSEC_ID_WATCHER = 3,
|
||||
VSEC_ID_CRASHLOG = 4,
|
||||
VSEC_ID_SDSI = 65,
|
||||
VSEC_ID_TPMI = 66,
|
||||
};
|
||||
|
||||
static enum intel_vsec_id intel_vsec_allow_list[] = {
|
||||
@ -71,6 +72,7 @@ static enum intel_vsec_id intel_vsec_allow_list[] = {
|
||||
VSEC_ID_WATCHER,
|
||||
VSEC_ID_CRASHLOG,
|
||||
VSEC_ID_SDSI,
|
||||
VSEC_ID_TPMI,
|
||||
};
|
||||
|
||||
static const char *intel_vsec_name(enum intel_vsec_id id)
|
||||
@ -88,6 +90,9 @@ static const char *intel_vsec_name(enum intel_vsec_id id)
|
||||
case VSEC_ID_SDSI:
|
||||
return "sdsi";
|
||||
|
||||
case VSEC_ID_TPMI:
|
||||
return "tpmi";
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -124,35 +129,48 @@ static void intel_vsec_remove_aux(void *data)
|
||||
auxiliary_device_uninit(data);
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(vsec_ida_lock);
|
||||
|
||||
static void intel_vsec_dev_release(struct device *dev)
|
||||
{
|
||||
struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev);
|
||||
|
||||
mutex_lock(&vsec_ida_lock);
|
||||
ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id);
|
||||
mutex_unlock(&vsec_ida_lock);
|
||||
|
||||
kfree(intel_vsec_dev->resource);
|
||||
kfree(intel_vsec_dev);
|
||||
}
|
||||
|
||||
static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *intel_vsec_dev,
|
||||
const char *name)
|
||||
int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
|
||||
struct intel_vsec_device *intel_vsec_dev,
|
||||
const char *name)
|
||||
{
|
||||
struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev;
|
||||
int ret, id;
|
||||
|
||||
mutex_lock(&vsec_ida_lock);
|
||||
ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL);
|
||||
mutex_unlock(&vsec_ida_lock);
|
||||
if (ret < 0) {
|
||||
kfree(intel_vsec_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!parent)
|
||||
parent = &pdev->dev;
|
||||
|
||||
auxdev->id = ret;
|
||||
auxdev->name = name;
|
||||
auxdev->dev.parent = &pdev->dev;
|
||||
auxdev->dev.parent = parent;
|
||||
auxdev->dev.release = intel_vsec_dev_release;
|
||||
|
||||
ret = auxiliary_device_init(auxdev);
|
||||
if (ret < 0) {
|
||||
mutex_lock(&vsec_ida_lock);
|
||||
ida_free(intel_vsec_dev->ida, auxdev->id);
|
||||
mutex_unlock(&vsec_ida_lock);
|
||||
kfree(intel_vsec_dev->resource);
|
||||
kfree(intel_vsec_dev);
|
||||
return ret;
|
||||
@ -164,7 +182,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux,
|
||||
ret = devm_add_action_or_reset(parent, intel_vsec_remove_aux,
|
||||
auxdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -177,6 +195,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, INTEL_VSEC);
|
||||
|
||||
static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header,
|
||||
struct intel_vsec_platform_info *info)
|
||||
@ -234,7 +253,8 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he
|
||||
else
|
||||
intel_vsec_dev->ida = &intel_vsec_ida;
|
||||
|
||||
return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id));
|
||||
return intel_vsec_add_aux(pdev, NULL, intel_vsec_dev,
|
||||
intel_vsec_name(header->id));
|
||||
}
|
||||
|
||||
static bool intel_vsec_walk_header(struct pci_dev *pdev,
|
||||
|
@ -38,8 +38,14 @@ struct intel_vsec_device {
|
||||
struct ida *ida;
|
||||
struct intel_vsec_platform_info *info;
|
||||
int num_resources;
|
||||
void *priv_data;
|
||||
size_t priv_data_size;
|
||||
};
|
||||
|
||||
int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
|
||||
struct intel_vsec_device *intel_vsec_dev,
|
||||
const char *name);
|
||||
|
||||
static inline struct intel_vsec_device *dev_to_ivdev(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct intel_vsec_device, auxdev.dev);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,10 @@
|
||||
#include <linux/wmi.h>
|
||||
#include <acpi/video.h>
|
||||
|
||||
static bool force;
|
||||
module_param(force, bool, 0444);
|
||||
MODULE_PARM_DESC(force, "Force loading (disable acpi_backlight=xxx checks");
|
||||
|
||||
/**
|
||||
* wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method
|
||||
* @w: Pointer to the struct wmi_device identified by %WMI_BRIGHTNESS_GUID
|
||||
@ -91,7 +95,7 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct
|
||||
int ret;
|
||||
|
||||
/* drivers/acpi/video_detect.c also checks that SOURCE == EC */
|
||||
if (acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec)
|
||||
if (!force && acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
|
@ -317,8 +317,8 @@ static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
copy_size = obj->buffer.length < sizeof(struct tlmi_pwdcfg) ?
|
||||
obj->buffer.length : sizeof(struct tlmi_pwdcfg);
|
||||
copy_size = min_t(size_t, obj->buffer.length, sizeof(struct tlmi_pwdcfg));
|
||||
|
||||
memcpy(pwdcfg, obj->buffer.pointer, copy_size);
|
||||
kfree(obj);
|
||||
|
||||
@ -1089,12 +1089,12 @@ static void tlmi_pwd_setting_release(struct kobject *kobj)
|
||||
kfree(setting);
|
||||
}
|
||||
|
||||
static struct kobj_type tlmi_attr_setting_ktype = {
|
||||
static const struct kobj_type tlmi_attr_setting_ktype = {
|
||||
.release = &tlmi_attr_setting_release,
|
||||
.sysfs_ops = &tlmi_kobj_sysfs_ops,
|
||||
};
|
||||
|
||||
static struct kobj_type tlmi_pwd_setting_ktype = {
|
||||
static const struct kobj_type tlmi_pwd_setting_ktype = {
|
||||
.release = &tlmi_pwd_setting_release,
|
||||
.sysfs_ops = &tlmi_kobj_sysfs_ops,
|
||||
};
|
||||
|
@ -203,7 +203,7 @@ static const struct sysfs_ops hub_sysfs_ops = {
|
||||
.show = hub_type_show,
|
||||
};
|
||||
|
||||
static struct kobj_type hub_attr_type = {
|
||||
static const struct kobj_type hub_attr_type = {
|
||||
.release = hub_release,
|
||||
.sysfs_ops = &hub_sysfs_ops,
|
||||
.default_groups = uv_hub_groups,
|
||||
@ -356,7 +356,7 @@ static const struct sysfs_ops uv_port_sysfs_ops = {
|
||||
.show = uv_port_type_show,
|
||||
};
|
||||
|
||||
static struct kobj_type uv_port_attr_type = {
|
||||
static const struct kobj_type uv_port_attr_type = {
|
||||
.release = uv_port_release,
|
||||
.sysfs_ops = &uv_port_sysfs_ops,
|
||||
.default_groups = uv_port_groups,
|
||||
@ -528,7 +528,7 @@ static const struct sysfs_ops uv_pci_top_sysfs_ops = {
|
||||
.show = pci_top_type_show,
|
||||
};
|
||||
|
||||
static struct kobj_type uv_pci_top_attr_type = {
|
||||
static const struct kobj_type uv_pci_top_attr_type = {
|
||||
.release = uv_pci_top_release,
|
||||
.sysfs_ops = &uv_pci_top_sysfs_ops,
|
||||
};
|
||||
|
@ -852,8 +852,8 @@ static const struct spwr_psy_properties spwr_psy_props_bat2_sb3 = {
|
||||
};
|
||||
|
||||
static const struct ssam_device_id surface_battery_match[] = {
|
||||
{ SSAM_SDEV(BAT, 0x01, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1 },
|
||||
{ SSAM_SDEV(BAT, 0x02, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 },
|
||||
{ SSAM_SDEV(BAT, SAM, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1 },
|
||||
{ SSAM_SDEV(BAT, KIP, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssam, surface_battery_match);
|
||||
|
@ -260,7 +260,7 @@ static const struct spwr_psy_properties spwr_psy_props_adp1 = {
|
||||
};
|
||||
|
||||
static const struct ssam_device_id surface_ac_match[] = {
|
||||
{ SSAM_SDEV(BAT, 0x01, 0x01, 0x01), (unsigned long)&spwr_psy_props_adp1 },
|
||||
{ SSAM_SDEV(BAT, SAM, 0x01, 0x01), (unsigned long)&spwr_psy_props_adp1 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ssam, surface_ac_match);
|
||||
|
30
include/linux/intel_tpmi.h
Normal file
30
include/linux/intel_tpmi.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* intel_tpmi.h: Intel TPMI core external interface
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_TPMI_H_
|
||||
#define _INTEL_TPMI_H_
|
||||
|
||||
/**
|
||||
* struct intel_tpmi_plat_info - Platform information for a TPMI device instance
|
||||
* @package_id: CPU Package id
|
||||
* @bus_number: PCI bus number
|
||||
* @device_number: PCI device number
|
||||
* @function_number: PCI function number
|
||||
*
|
||||
* Structure to store platform data for a TPMI device instance. This
|
||||
* struct is used to return data via tpmi_get_platform_data().
|
||||
*/
|
||||
struct intel_tpmi_plat_info {
|
||||
u8 package_id;
|
||||
u8 bus_number;
|
||||
u8 device_number;
|
||||
u8 function_number;
|
||||
};
|
||||
|
||||
struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev);
|
||||
struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int index);
|
||||
int tpmi_get_resource_count(struct auxiliary_device *auxdev);
|
||||
|
||||
#endif
|
@ -39,6 +39,21 @@ enum led_default_state {
|
||||
LEDS_DEFSTATE_KEEP = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct led_lookup_data - represents a single LED lookup entry
|
||||
*
|
||||
* @list: internal list of all LED lookup entries
|
||||
* @provider: name of led_classdev providing the LED
|
||||
* @dev_id: name of the device associated with this LED
|
||||
* @con_id: name of the LED from the device's point of view
|
||||
*/
|
||||
struct led_lookup_data {
|
||||
struct list_head list;
|
||||
const char *provider;
|
||||
const char *dev_id;
|
||||
const char *con_id;
|
||||
};
|
||||
|
||||
struct led_init_data {
|
||||
/* device fwnode handle */
|
||||
struct fwnode_handle *fwnode;
|
||||
@ -211,6 +226,12 @@ void devm_led_classdev_unregister(struct device *parent,
|
||||
void led_classdev_suspend(struct led_classdev *led_cdev);
|
||||
void led_classdev_resume(struct led_classdev *led_cdev);
|
||||
|
||||
void led_add_lookup(struct led_lookup_data *led_lookup);
|
||||
void led_remove_lookup(struct led_lookup_data *led_lookup);
|
||||
|
||||
struct led_classdev *__must_check led_get(struct device *dev, char *con_id);
|
||||
struct led_classdev *__must_check devm_led_get(struct device *dev, char *con_id);
|
||||
|
||||
extern struct led_classdev *of_led_get(struct device_node *np, int index);
|
||||
extern void led_put(struct led_classdev *led_cdev);
|
||||
struct led_classdev *__must_check devm_of_led_get(struct device *dev,
|
||||
|
@ -216,6 +216,7 @@ struct mlxreg_core_platform_data {
|
||||
* @mask_low: low aggregation interrupt common mask;
|
||||
* @deferred_nr: I2C adapter number must be exist prior probing execution;
|
||||
* @shift_nr: I2C adapter numbers must be incremented by this value;
|
||||
* @addr: mapped resource address;
|
||||
* @handle: handle to be passed by callback;
|
||||
* @completion_notify: callback to notify when platform driver probing is done;
|
||||
*/
|
||||
@ -230,6 +231,7 @@ struct mlxreg_core_hotplug_platform_data {
|
||||
u32 mask_low;
|
||||
int deferred_nr;
|
||||
int shift_nr;
|
||||
void __iomem *addr;
|
||||
void *handle;
|
||||
int (*completion_notify)(void *handle, int id);
|
||||
};
|
||||
|
@ -8,10 +8,13 @@
|
||||
#ifndef __PLATFORM_DATA_X86_SOC_H
|
||||
#define __PLATFORM_DATA_X86_SOC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_X86)
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/intel-family.h>
|
||||
|
||||
#define SOC_INTEL_IS_CPU(soc, type) \
|
||||
static inline bool soc_intel_is_##soc(void) \
|
||||
@ -34,6 +37,8 @@ SOC_INTEL_IS_CPU(apl, ATOM_GOLDMONT);
|
||||
SOC_INTEL_IS_CPU(glk, ATOM_GOLDMONT_PLUS);
|
||||
SOC_INTEL_IS_CPU(cml, KABYLAKE_L);
|
||||
|
||||
#undef SOC_INTEL_IS_CPU
|
||||
|
||||
#else /* IS_ENABLED(CONFIG_X86) */
|
||||
|
||||
static inline bool soc_intel_is_byt(void)
|
||||
|
@ -207,17 +207,17 @@ static inline int ssam_request_sync_wait(struct ssam_request_sync *rqst)
|
||||
return rqst->status;
|
||||
}
|
||||
|
||||
int ssam_request_sync(struct ssam_controller *ctrl,
|
||||
const struct ssam_request *spec,
|
||||
struct ssam_response *rsp);
|
||||
int ssam_request_do_sync(struct ssam_controller *ctrl,
|
||||
const struct ssam_request *spec,
|
||||
struct ssam_response *rsp);
|
||||
|
||||
int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
|
||||
const struct ssam_request *spec,
|
||||
struct ssam_response *rsp,
|
||||
struct ssam_span *buf);
|
||||
int ssam_request_do_sync_with_buffer(struct ssam_controller *ctrl,
|
||||
const struct ssam_request *spec,
|
||||
struct ssam_response *rsp,
|
||||
struct ssam_span *buf);
|
||||
|
||||
/**
|
||||
* ssam_request_sync_onstack - Execute a synchronous request on the stack.
|
||||
* ssam_request_do_sync_onstack - Execute a synchronous request on the stack.
|
||||
* @ctrl: The controller via which the request is submitted.
|
||||
* @rqst: The request specification.
|
||||
* @rsp: The response buffer.
|
||||
@ -227,7 +227,7 @@ int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
|
||||
* fully initializes it via the provided request specification, submits it,
|
||||
* and finally waits for its completion before returning its status. This
|
||||
* helper macro essentially allocates the request message buffer on the stack
|
||||
* and then calls ssam_request_sync_with_buffer().
|
||||
* and then calls ssam_request_do_sync_with_buffer().
|
||||
*
|
||||
* Note: The @payload_len parameter specifies the maximum payload length, used
|
||||
* for buffer allocation. The actual payload length may be smaller.
|
||||
@ -235,12 +235,12 @@ int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
|
||||
* Return: Returns the status of the request or any failure during setup, i.e.
|
||||
* zero on success and a negative value on failure.
|
||||
*/
|
||||
#define ssam_request_sync_onstack(ctrl, rqst, rsp, payload_len) \
|
||||
#define ssam_request_do_sync_onstack(ctrl, rqst, rsp, payload_len) \
|
||||
({ \
|
||||
u8 __data[SSH_COMMAND_MESSAGE_LENGTH(payload_len)]; \
|
||||
struct ssam_span __buf = { &__data[0], ARRAY_SIZE(__data) }; \
|
||||
\
|
||||
ssam_request_sync_with_buffer(ctrl, rqst, rsp, &__buf); \
|
||||
ssam_request_do_sync_with_buffer(ctrl, rqst, rsp, &__buf); \
|
||||
})
|
||||
|
||||
/**
|
||||
@ -349,7 +349,7 @@ struct ssam_request_spec_md {
|
||||
* zero on success and negative on failure. The ``ctrl`` parameter is the
|
||||
* controller via which the request is being sent.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_N(name, spec...) \
|
||||
@ -366,7 +366,7 @@ struct ssam_request_spec_md {
|
||||
rqst.length = 0; \
|
||||
rqst.payload = NULL; \
|
||||
\
|
||||
return ssam_request_sync_onstack(ctrl, &rqst, NULL, 0); \
|
||||
return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, 0); \
|
||||
}
|
||||
|
||||
/**
|
||||
@ -389,7 +389,7 @@ struct ssam_request_spec_md {
|
||||
* parameter is the controller via which the request is sent. The request
|
||||
* argument is specified via the ``arg`` pointer.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_W(name, atype, spec...) \
|
||||
@ -406,8 +406,8 @@ struct ssam_request_spec_md {
|
||||
rqst.length = sizeof(atype); \
|
||||
rqst.payload = (u8 *)arg; \
|
||||
\
|
||||
return ssam_request_sync_onstack(ctrl, &rqst, NULL, \
|
||||
sizeof(atype)); \
|
||||
return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, \
|
||||
sizeof(atype)); \
|
||||
}
|
||||
|
||||
/**
|
||||
@ -430,7 +430,7 @@ struct ssam_request_spec_md {
|
||||
* the controller via which the request is sent. The request's return value is
|
||||
* written to the memory pointed to by the ``ret`` parameter.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_R(name, rtype, spec...) \
|
||||
@ -453,7 +453,7 @@ struct ssam_request_spec_md {
|
||||
rsp.length = 0; \
|
||||
rsp.pointer = (u8 *)ret; \
|
||||
\
|
||||
status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, 0); \
|
||||
status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, 0); \
|
||||
if (status) \
|
||||
return status; \
|
||||
\
|
||||
@ -491,7 +491,7 @@ struct ssam_request_spec_md {
|
||||
* request argument is specified via the ``arg`` pointer. The request's return
|
||||
* value is written to the memory pointed to by the ``ret`` parameter.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_WR(name, atype, rtype, spec...) \
|
||||
@ -514,7 +514,7 @@ struct ssam_request_spec_md {
|
||||
rsp.length = 0; \
|
||||
rsp.pointer = (u8 *)ret; \
|
||||
\
|
||||
status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \
|
||||
status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \
|
||||
if (status) \
|
||||
return status; \
|
||||
\
|
||||
@ -550,7 +550,7 @@ struct ssam_request_spec_md {
|
||||
* parameter is the controller via which the request is sent, ``tid`` the
|
||||
* target ID for the request, and ``iid`` the instance ID.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_MD_N(name, spec...) \
|
||||
@ -567,7 +567,7 @@ struct ssam_request_spec_md {
|
||||
rqst.length = 0; \
|
||||
rqst.payload = NULL; \
|
||||
\
|
||||
return ssam_request_sync_onstack(ctrl, &rqst, NULL, 0); \
|
||||
return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, 0); \
|
||||
}
|
||||
|
||||
/**
|
||||
@ -592,7 +592,7 @@ struct ssam_request_spec_md {
|
||||
* ``tid`` the target ID for the request, and ``iid`` the instance ID. The
|
||||
* request argument is specified via the ``arg`` pointer.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_MD_W(name, atype, spec...) \
|
||||
@ -609,7 +609,7 @@ struct ssam_request_spec_md {
|
||||
rqst.length = sizeof(atype); \
|
||||
rqst.payload = (u8 *)arg; \
|
||||
\
|
||||
return ssam_request_sync_onstack(ctrl, &rqst, NULL, \
|
||||
return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, \
|
||||
sizeof(atype)); \
|
||||
}
|
||||
|
||||
@ -635,7 +635,7 @@ struct ssam_request_spec_md {
|
||||
* the target ID for the request, and ``iid`` the instance ID. The request's
|
||||
* return value is written to the memory pointed to by the ``ret`` parameter.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_MD_R(name, rtype, spec...) \
|
||||
@ -658,7 +658,7 @@ struct ssam_request_spec_md {
|
||||
rsp.length = 0; \
|
||||
rsp.pointer = (u8 *)ret; \
|
||||
\
|
||||
status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, 0); \
|
||||
status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, 0); \
|
||||
if (status) \
|
||||
return status; \
|
||||
\
|
||||
@ -698,7 +698,7 @@ struct ssam_request_spec_md {
|
||||
* The request argument is specified via the ``arg`` pointer. The request's
|
||||
* return value is written to the memory pointed to by the ``ret`` parameter.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_MD_WR(name, atype, rtype, spec...) \
|
||||
@ -722,7 +722,7 @@ struct ssam_request_spec_md {
|
||||
rsp.length = 0; \
|
||||
rsp.pointer = (u8 *)ret; \
|
||||
\
|
||||
status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \
|
||||
status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \
|
||||
if (status) \
|
||||
return status; \
|
||||
\
|
||||
@ -912,10 +912,10 @@ enum ssam_event_mask {
|
||||
})
|
||||
|
||||
#define SSAM_EVENT_REGISTRY_SAM \
|
||||
SSAM_EVENT_REGISTRY(SSAM_SSH_TC_SAM, 0x01, 0x0b, 0x0c)
|
||||
SSAM_EVENT_REGISTRY(SSAM_SSH_TC_SAM, SSAM_SSH_TID_SAM, 0x0b, 0x0c)
|
||||
|
||||
#define SSAM_EVENT_REGISTRY_KIP \
|
||||
SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, 0x02, 0x27, 0x28)
|
||||
SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, SSAM_SSH_TID_KIP, 0x27, 0x28)
|
||||
|
||||
#define SSAM_EVENT_REGISTRY_REG(tid)\
|
||||
SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, tid, 0x01, 0x02)
|
||||
|
@ -68,9 +68,9 @@ struct ssam_device_uid {
|
||||
* match_flags member of the device ID structure. Do not use them directly
|
||||
* with struct ssam_device_id or struct ssam_device_uid.
|
||||
*/
|
||||
#define SSAM_ANY_TID 0xffff
|
||||
#define SSAM_ANY_IID 0xffff
|
||||
#define SSAM_ANY_FUN 0xffff
|
||||
#define SSAM_SSH_TID_ANY 0xffff
|
||||
#define SSAM_SSH_IID_ANY 0xffff
|
||||
#define SSAM_SSH_FUN_ANY 0xffff
|
||||
|
||||
/**
|
||||
* SSAM_DEVICE() - Initialize a &struct ssam_device_id with the given
|
||||
@ -83,25 +83,25 @@ struct ssam_device_uid {
|
||||
*
|
||||
* Initializes a &struct ssam_device_id with the given parameters. See &struct
|
||||
* ssam_device_uid for details regarding the parameters. The special values
|
||||
* %SSAM_ANY_TID, %SSAM_ANY_IID, and %SSAM_ANY_FUN can be used to specify that
|
||||
* %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and %SSAM_SSH_FUN_ANY can be used to specify that
|
||||
* matching should ignore target ID, instance ID, and/or sub-function,
|
||||
* respectively. This macro initializes the ``match_flags`` field based on the
|
||||
* given parameters.
|
||||
*
|
||||
* Note: The parameters @d and @cat must be valid &u8 values, the parameters
|
||||
* @tid, @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID,
|
||||
* %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not
|
||||
* @tid, @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY,
|
||||
* %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values are not
|
||||
* allowed.
|
||||
*/
|
||||
#define SSAM_DEVICE(d, cat, tid, iid, fun) \
|
||||
.match_flags = (((tid) != SSAM_ANY_TID) ? SSAM_MATCH_TARGET : 0) \
|
||||
| (((iid) != SSAM_ANY_IID) ? SSAM_MATCH_INSTANCE : 0) \
|
||||
| (((fun) != SSAM_ANY_FUN) ? SSAM_MATCH_FUNCTION : 0), \
|
||||
.match_flags = (((tid) != SSAM_SSH_TID_ANY) ? SSAM_MATCH_TARGET : 0) \
|
||||
| (((iid) != SSAM_SSH_IID_ANY) ? SSAM_MATCH_INSTANCE : 0) \
|
||||
| (((fun) != SSAM_SSH_FUN_ANY) ? SSAM_MATCH_FUNCTION : 0), \
|
||||
.domain = d, \
|
||||
.category = cat, \
|
||||
.target = __builtin_choose_expr((tid) != SSAM_ANY_TID, (tid), 0), \
|
||||
.instance = __builtin_choose_expr((iid) != SSAM_ANY_IID, (iid), 0), \
|
||||
.function = __builtin_choose_expr((fun) != SSAM_ANY_FUN, (fun), 0)
|
||||
.target = __builtin_choose_expr((tid) != SSAM_SSH_TID_ANY, (tid), 0), \
|
||||
.instance = __builtin_choose_expr((iid) != SSAM_SSH_IID_ANY, (iid), 0), \
|
||||
.function = __builtin_choose_expr((fun) != SSAM_SSH_FUN_ANY, (fun), 0)
|
||||
|
||||
/**
|
||||
* SSAM_VDEV() - Initialize a &struct ssam_device_id as virtual device with
|
||||
@ -113,18 +113,18 @@ struct ssam_device_uid {
|
||||
*
|
||||
* Initializes a &struct ssam_device_id with the given parameters in the
|
||||
* virtual domain. See &struct ssam_device_uid for details regarding the
|
||||
* parameters. The special values %SSAM_ANY_TID, %SSAM_ANY_IID, and
|
||||
* %SSAM_ANY_FUN can be used to specify that matching should ignore target ID,
|
||||
* parameters. The special values %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and
|
||||
* %SSAM_SSH_FUN_ANY can be used to specify that matching should ignore target ID,
|
||||
* instance ID, and/or sub-function, respectively. This macro initializes the
|
||||
* ``match_flags`` field based on the given parameters.
|
||||
*
|
||||
* Note: The parameter @cat must be a valid &u8 value, the parameters @tid,
|
||||
* @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID,
|
||||
* %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not
|
||||
* @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY,
|
||||
* %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values are not
|
||||
* allowed.
|
||||
*/
|
||||
#define SSAM_VDEV(cat, tid, iid, fun) \
|
||||
SSAM_DEVICE(SSAM_DOMAIN_VIRTUAL, SSAM_VIRTUAL_TC_##cat, tid, iid, fun)
|
||||
SSAM_DEVICE(SSAM_DOMAIN_VIRTUAL, SSAM_VIRTUAL_TC_##cat, SSAM_SSH_TID_##tid, iid, fun)
|
||||
|
||||
/**
|
||||
* SSAM_SDEV() - Initialize a &struct ssam_device_id as physical SSH device
|
||||
@ -136,18 +136,18 @@ struct ssam_device_uid {
|
||||
*
|
||||
* Initializes a &struct ssam_device_id with the given parameters in the SSH
|
||||
* domain. See &struct ssam_device_uid for details regarding the parameters.
|
||||
* The special values %SSAM_ANY_TID, %SSAM_ANY_IID, and %SSAM_ANY_FUN can be
|
||||
* used to specify that matching should ignore target ID, instance ID, and/or
|
||||
* sub-function, respectively. This macro initializes the ``match_flags``
|
||||
* field based on the given parameters.
|
||||
* The special values %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and
|
||||
* %SSAM_SSH_FUN_ANY can be used to specify that matching should ignore target
|
||||
* ID, instance ID, and/or sub-function, respectively. This macro initializes
|
||||
* the ``match_flags`` field based on the given parameters.
|
||||
*
|
||||
* Note: The parameter @cat must be a valid &u8 value, the parameters @tid,
|
||||
* @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID,
|
||||
* %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not
|
||||
* allowed.
|
||||
* @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY,
|
||||
* %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values
|
||||
* are not allowed.
|
||||
*/
|
||||
#define SSAM_SDEV(cat, tid, iid, fun) \
|
||||
SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, tid, iid, fun)
|
||||
SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, SSAM_SSH_TID_##tid, iid, fun)
|
||||
|
||||
/*
|
||||
* enum ssam_device_flags - Flags for SSAM client devices.
|
||||
@ -456,7 +456,7 @@ static inline int ssam_device_register_clients(struct ssam_device *sdev)
|
||||
* device of the request and by association the controller via which the
|
||||
* request is sent.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_CL_N(name, spec...) \
|
||||
@ -490,7 +490,7 @@ static inline int ssam_device_register_clients(struct ssam_device *sdev)
|
||||
* which the request is sent. The request's argument is specified via the
|
||||
* ``arg`` pointer.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_CL_W(name, atype, spec...) \
|
||||
@ -524,7 +524,7 @@ static inline int ssam_device_register_clients(struct ssam_device *sdev)
|
||||
* the request is sent. The request's return value is written to the memory
|
||||
* pointed to by the ``ret`` parameter.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_CL_R(name, rtype, spec...) \
|
||||
@ -560,7 +560,7 @@ static inline int ssam_device_register_clients(struct ssam_device *sdev)
|
||||
* specified via the ``arg`` pointer. The request's return value is written to
|
||||
* the memory pointed to by the ``ret`` parameter.
|
||||
*
|
||||
* Refer to ssam_request_sync_onstack() for more details on the behavior of
|
||||
* Refer to ssam_request_do_sync_onstack() for more details on the behavior of
|
||||
* the generated function.
|
||||
*/
|
||||
#define SSAM_DEFINE_SYNC_REQUEST_CL_WR(name, atype, rtype, spec...) \
|
||||
|
@ -83,23 +83,21 @@ enum ssh_payload_type {
|
||||
|
||||
/**
|
||||
* struct ssh_command - Payload of a command-type frame.
|
||||
* @type: The type of the payload. See &enum ssh_payload_type. Should be
|
||||
* SSH_PLD_TYPE_CMD for this struct.
|
||||
* @tc: Command target category.
|
||||
* @tid_out: Output target ID. Should be zero if this an incoming (EC to host)
|
||||
* message.
|
||||
* @tid_in: Input target ID. Should be zero if this is an outgoing (host to
|
||||
* EC) message.
|
||||
* @iid: Instance ID.
|
||||
* @rqid: Request ID. Used to match requests with responses and differentiate
|
||||
* between responses and events.
|
||||
* @cid: Command ID.
|
||||
* @type: The type of the payload. See &enum ssh_payload_type. Should be
|
||||
* SSH_PLD_TYPE_CMD for this struct.
|
||||
* @tc: Command target category.
|
||||
* @tid: Target ID. Indicates the target of the message.
|
||||
* @sid: Source ID. Indicates the source of the message.
|
||||
* @iid: Instance ID.
|
||||
* @rqid: Request ID. Used to match requests with responses and differentiate
|
||||
* between responses and events.
|
||||
* @cid: Command ID.
|
||||
*/
|
||||
struct ssh_command {
|
||||
u8 type;
|
||||
u8 tc;
|
||||
u8 tid_out;
|
||||
u8 tid_in;
|
||||
u8 tid;
|
||||
u8 sid;
|
||||
u8 iid;
|
||||
__le16 rqid;
|
||||
u8 cid;
|
||||
@ -280,6 +278,22 @@ struct ssam_span {
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ssam_ssh_tid - Target/source IDs for Serial Hub messages.
|
||||
* @SSAM_SSH_TID_HOST: We as the kernel Serial Hub driver.
|
||||
* @SSAM_SSH_TID_SAM: The Surface Aggregator EC.
|
||||
* @SSAM_SSH_TID_KIP: Keyboard and perihperal controller.
|
||||
* @SSAM_SSH_TID_DEBUG: Debug connector.
|
||||
* @SSAM_SSH_TID_SURFLINK: SurfLink connector.
|
||||
*/
|
||||
enum ssam_ssh_tid {
|
||||
SSAM_SSH_TID_HOST = 0x00,
|
||||
SSAM_SSH_TID_SAM = 0x01,
|
||||
SSAM_SSH_TID_KIP = 0x02,
|
||||
SSAM_SSH_TID_DEBUG = 0x03,
|
||||
SSAM_SSH_TID_SURFLINK = 0x04,
|
||||
};
|
||||
|
||||
/*
|
||||
* Known SSH/EC target categories.
|
||||
*
|
||||
|
@ -38,6 +38,7 @@ struct v4l2_subdev;
|
||||
struct v4l2_subdev_fh;
|
||||
struct tuner_setup;
|
||||
struct v4l2_mbus_frame_desc;
|
||||
struct led_classdev;
|
||||
|
||||
/**
|
||||
* struct v4l2_decode_vbi_line - used to decode_vbi_line
|
||||
@ -941,6 +942,7 @@ struct v4l2_subdev_platform_data {
|
||||
* @state_lock: A pointer to a lock used for all the subdev's states, set by the
|
||||
* driver. This is optional. If NULL, each state instance will get
|
||||
* a lock of its own.
|
||||
* @privacy_led: Optional pointer to a LED classdev for the privacy LED for sensors.
|
||||
* @active_state: Active state for the subdev (NULL for subdevs tracking the
|
||||
* state internally). Initialized by calling
|
||||
* v4l2_subdev_init_finalize().
|
||||
@ -982,6 +984,8 @@ struct v4l2_subdev {
|
||||
* appropriate functions.
|
||||
*/
|
||||
|
||||
struct led_classdev *privacy_led;
|
||||
|
||||
/*
|
||||
* TODO: active_state should most likely be changed from a pointer to an
|
||||
* embedded field. For the time being it's kept as a pointer to more
|
||||
|
@ -247,7 +247,6 @@ int hfi_main(void)
|
||||
struct nl_cb *cb;
|
||||
int err = 0;
|
||||
int mcast_id;
|
||||
int no_block = 0;
|
||||
|
||||
if (!check_hf_suport()) {
|
||||
fprintf(stderr, "CPU Doesn't support HFI\n");
|
||||
@ -287,9 +286,6 @@ int hfi_main(void)
|
||||
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_check_handler, 0);
|
||||
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handle_event, NULL);
|
||||
|
||||
if (no_block)
|
||||
nl_socket_set_nonblocking(sock);
|
||||
|
||||
debug_printf("hfi is initialized\n");
|
||||
|
||||
while (!_hfi_exit && !err) {
|
||||
|
@ -15,7 +15,7 @@ struct process_cmd_struct {
|
||||
int arg;
|
||||
};
|
||||
|
||||
static const char *version_str = "v1.13";
|
||||
static const char *version_str = "v1.14";
|
||||
|
||||
static const int supported_api_ver = 1;
|
||||
static struct isst_if_platform_info isst_platform_info;
|
||||
@ -110,7 +110,7 @@ int is_skx_based_platform(void)
|
||||
|
||||
int is_spr_platform(void)
|
||||
{
|
||||
if (cpu_model == 0x8F)
|
||||
if (cpu_model == 0x8F || cpu_model == 0xCF)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@ -383,11 +383,11 @@ void set_isst_id(struct isst_id *id, int cpu)
|
||||
id->cpu = cpu;
|
||||
|
||||
id->pkg = get_physical_package_id(cpu);
|
||||
if (id < 0 || id->pkg >= MAX_PACKAGE_COUNT)
|
||||
if (id->pkg >= MAX_PACKAGE_COUNT)
|
||||
id->pkg = -1;
|
||||
|
||||
id->die = get_physical_die_id(cpu);
|
||||
if (id < 0 || id->die >= MAX_DIE_PER_PACKAGE)
|
||||
if (id->die >= MAX_DIE_PER_PACKAGE)
|
||||
id->die = -1;
|
||||
}
|
||||
|
||||
@ -413,6 +413,33 @@ int get_topo_max_cpus(void)
|
||||
return topo_max_cpus;
|
||||
}
|
||||
|
||||
static unsigned int is_cpu_online(int cpu)
|
||||
{
|
||||
char buffer[128];
|
||||
int fd, ret;
|
||||
unsigned char online;
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"/sys/devices/system/cpu/cpu%d/online", cpu);
|
||||
|
||||
fd = open(buffer, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
ret = read(fd, &online, sizeof(online));
|
||||
close(fd);
|
||||
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
|
||||
if (online == '1')
|
||||
online = 1;
|
||||
else
|
||||
online = 0;
|
||||
|
||||
return online;
|
||||
}
|
||||
|
||||
void set_cpu_online_offline(int cpu, int state)
|
||||
{
|
||||
char buffer[128];
|
||||
@ -1292,6 +1319,34 @@ static void dump_isst_config(int arg)
|
||||
isst_ctdp_display_information_end(outf);
|
||||
}
|
||||
|
||||
static int set_uncore_min_max(struct isst_id *id, int max, int freq)
|
||||
{
|
||||
char buffer[128], freq_str[16];
|
||||
int fd, ret, len;
|
||||
|
||||
if (max)
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/max_freq_khz", id->pkg, id->die);
|
||||
else
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/min_freq_khz", id->pkg, id->die);
|
||||
|
||||
fd = open(buffer, O_WRONLY);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
snprintf(freq_str, sizeof(freq_str), "%d", freq);
|
||||
len = strlen(freq_str);
|
||||
ret = write(fd, freq_str, len);
|
||||
if (ret == -1) {
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adjust_scaling_max_from_base_freq(int cpu);
|
||||
|
||||
static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
|
||||
@ -1313,6 +1368,14 @@ static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, vo
|
||||
/* Wait for updated base frequencies */
|
||||
usleep(2000);
|
||||
|
||||
/* Adjusting uncore freq */
|
||||
isst_get_uncore_p0_p1_info(id, tdp_level, &ctdp_level);
|
||||
if (ctdp_level.uncore_pm)
|
||||
set_uncore_min_max(id, 0, ctdp_level.uncore_pm * 100000);
|
||||
|
||||
if (ctdp_level.uncore_p0)
|
||||
set_uncore_min_max(id, 1, ctdp_level.uncore_p0 * 100000);
|
||||
|
||||
fprintf(stderr, "Option is set to online/offline\n");
|
||||
ctdp_level.core_cpumask_size =
|
||||
alloc_cpu_set(&ctdp_level.core_cpumask);
|
||||
@ -1583,6 +1646,7 @@ static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, in
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
min_freq[15] = '\0';
|
||||
len = strlen(min_freq);
|
||||
ret = write(fd, min_freq, len);
|
||||
if (ret == -1) {
|
||||
@ -1602,6 +1666,9 @@ static void set_scaling_min_to_cpuinfo_max(struct isst_id *id)
|
||||
if (!is_cpu_in_power_domain(i, id))
|
||||
continue;
|
||||
|
||||
if (is_cpu_online(i) != 1)
|
||||
continue;
|
||||
|
||||
adjust_scaling_max_from_base_freq(i);
|
||||
set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0);
|
||||
adjust_scaling_min_from_base_freq(i);
|
||||
@ -1616,6 +1683,9 @@ static void set_scaling_min_to_cpuinfo_min(struct isst_id *id)
|
||||
if (!is_cpu_in_power_domain(i, id))
|
||||
continue;
|
||||
|
||||
if (is_cpu_online(i) != 1)
|
||||
continue;
|
||||
|
||||
adjust_scaling_max_from_base_freq(i);
|
||||
set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0);
|
||||
}
|
||||
@ -2015,6 +2085,7 @@ static void set_fact_enable(int arg)
|
||||
if (len < 0)
|
||||
continue;
|
||||
|
||||
sibling_list[127] = '\0';
|
||||
cpu_str = strtok(sibling_list, ",");
|
||||
while (cpu_str != NULL) {
|
||||
int cpu;
|
||||
@ -2031,6 +2102,9 @@ static void set_fact_enable(int arg)
|
||||
if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
|
||||
continue;
|
||||
|
||||
if (is_cpu_online(i) != 1)
|
||||
continue;
|
||||
|
||||
set_isst_id(&id, i);
|
||||
ret = set_clos_param(&id, 0, 0, 0, 0, 0xff);
|
||||
if (ret)
|
||||
|
@ -156,6 +156,29 @@ void isst_get_uncore_p0_p1_info(struct isst_id *id, int config_index,
|
||||
{
|
||||
unsigned int resp;
|
||||
int ret;
|
||||
|
||||
ctdp_level->uncore_pm = 0;
|
||||
ctdp_level->uncore_p0 = 0;
|
||||
ctdp_level->uncore_p1 = 0;
|
||||
|
||||
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
|
||||
CONFIG_TDP_GET_RATIO_INFO, 0,
|
||||
(BIT(16) | config_index), &resp);
|
||||
if (ret)
|
||||
goto try_uncore_mbox;
|
||||
|
||||
ctdp_level->uncore_p0 = resp & GENMASK(7, 0);
|
||||
ctdp_level->uncore_p1 = (resp & GENMASK(15, 8)) >> 8;
|
||||
ctdp_level->uncore_pm = (resp & GENMASK(31, 24)) >> 24;
|
||||
|
||||
debug_printf(
|
||||
"cpu:%d ctdp:%d CONFIG_TDP_GET_RATIO_INFO resp:%x uncore p0:%d uncore p1:%d uncore pm:%d\n",
|
||||
id->cpu, config_index, resp, ctdp_level->uncore_p0, ctdp_level->uncore_p1,
|
||||
ctdp_level->uncore_pm);
|
||||
|
||||
return;
|
||||
|
||||
try_uncore_mbox:
|
||||
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
|
||||
CONFIG_TDP_GET_UNCORE_P0_P1_INFO, 0,
|
||||
config_index, &resp);
|
||||
|
@ -174,8 +174,7 @@ static void daemonize(char *rundir, char *pidfile)
|
||||
close(i);
|
||||
|
||||
i = open("/dev/null", O_RDWR);
|
||||
ret = dup(i);
|
||||
if (ret == -1)
|
||||
if (i < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
ret = dup(i);
|
||||
|
@ -423,10 +423,10 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level
|
||||
format_and_print(outf, level + 2, header, value);
|
||||
}
|
||||
|
||||
if (ctdp_level->uncore_p1) {
|
||||
if (ctdp_level->uncore_pm) {
|
||||
snprintf(header, sizeof(header), "uncore-frequency-min(MHz)");
|
||||
snprintf(value, sizeof(value), "%d",
|
||||
ctdp_level->uncore_p1 * DISP_FREQ_MULTIPLIER);
|
||||
ctdp_level->uncore_pm * DISP_FREQ_MULTIPLIER);
|
||||
format_and_print(outf, level + 2, header, value);
|
||||
}
|
||||
|
||||
@ -437,6 +437,13 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level
|
||||
format_and_print(outf, level + 2, header, value);
|
||||
}
|
||||
|
||||
if (ctdp_level->uncore_p1) {
|
||||
snprintf(header, sizeof(header), "uncore-frequency-base(MHz)");
|
||||
snprintf(value, sizeof(value), "%d",
|
||||
ctdp_level->uncore_p1 * DISP_FREQ_MULTIPLIER);
|
||||
format_and_print(outf, level + 2, header, value);
|
||||
}
|
||||
|
||||
if (ctdp_level->mem_freq) {
|
||||
snprintf(header, sizeof(header), "mem-frequency(MHz)");
|
||||
snprintf(value, sizeof(value), "%d",
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define CONFIG_TDP_GET_UNCORE_P0_P1_INFO 0X09
|
||||
#define CONFIG_TDP_GET_P1_INFO 0x0a
|
||||
#define CONFIG_TDP_GET_MEM_FREQ 0x0b
|
||||
#define CONFIG_TDP_GET_RATIO_INFO 0x0c
|
||||
|
||||
#define CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES 0x10
|
||||
#define CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS 0x11
|
||||
@ -144,6 +145,7 @@ struct isst_pkg_ctdp_level_info {
|
||||
int t_proc_hot;
|
||||
int uncore_p0;
|
||||
int uncore_p1;
|
||||
int uncore_pm;
|
||||
int sse_p1;
|
||||
int avx2_p1;
|
||||
int avx512_p1;
|
||||
@ -208,6 +210,8 @@ extern int isst_get_ctdp_control(struct isst_id *id, int config_index,
|
||||
struct isst_pkg_ctdp_level_info *ctdp_level);
|
||||
extern int isst_get_coremask_info(struct isst_id *id, int config_index,
|
||||
struct isst_pkg_ctdp_level_info *ctdp_level);
|
||||
extern void isst_get_uncore_p0_p1_info(struct isst_id *id, int config_index,
|
||||
struct isst_pkg_ctdp_level_info *ctdp_level);
|
||||
extern int isst_get_process_ctdp(struct isst_id *id, int tdp_level,
|
||||
struct isst_pkg_ctdp *pkg_dev);
|
||||
extern void isst_get_process_ctdp_complete(struct isst_id *id,
|
||||
|
Loading…
Reference in New Issue
Block a user