요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
=================================
Intel Integrated Sensor Hub (ISH)
=================================
A sensor hub enables the ability to offload sensor polling and algorithm
processing to a dedicated low power co-processor. This allows the core
processor to go into low power modes more often, resulting in increased
battery life.
There are many vendors providing external sensor hubs conforming to HID
Sensor usage tables. These may be found in tablets, 2-in-1 convertible laptops
and embedded products. Linux has had this support since Linux 3.9.
Intel® introduced integrated sensor hubs as a part of the SoC starting from
Cherry Trail and now supported on multiple generations of CPU packages. There
are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
These ISH also comply to HID sensor specification, but the difference is the
transport protocol used for communication. The current external sensor hubs
mainly use HID over I2C or USB. But ISH doesn't use either I2C or USB.
Overview
========
Using a analogy with a usbhid implementation, the ISH follows a similar model
for a very high speed communication::
----------------- ----------------------
| USB HID | --> | ISH HID |
----------------- ----------------------
----------------- ----------------------
| USB protocol | --> | ISH Transport |
----------------- ----------------------
----------------- ----------------------
| EHCI/XHCI | --> | ISH IPC |
----------------- ----------------------
PCI PCI
----------------- ----------------------
|Host controller| --> | ISH processor |
----------------- ----------------------
USB Link
----------------- ----------------------
| USB End points| --> | ISH Clients |
----------------- ----------------------
Like USB protocol provides a method for device enumeration, link management
and user data encapsulation, the ISH also provides similar services. But it is
very light weight tailored to manage and communicate with ISH client
applications implemented in the firmware.
The ISH allows multiple sensor management applications executing in the
firmware. Like USB endpoints the messaging can be to/from a client. As part of
enumeration process, these clients are identified. These clients can be simple
HID sensor applications, sensor calibration applications or sensor firmware
update applications.
The implementation model is similar, like USB bus, ISH transport is also
implemented as a bus. Each client application executing in the ISH processor
is registered as a device on this bus. The driver, which binds each device
(ISH HID driver) identifies the device type and registers with the HID core.
ISH Implementation: Block Diagram
=================================
::
---------------------------
| User Space Applications |
---------------------------
----------------IIO ABI----------------
--------------------------
| IIO Sensor Drivers |
--------------------------
--------------------------
| IIO core |
--------------------------
--------------------------
| HID Sensor Hub MFD |
--------------------------
--------------------------
| HID Core |
--------------------------
--------------------------
| HID over ISH Client |
--------------------------
--------------------------
| ISH Transport (ISHTP) |
--------------------------
--------------------------
| IPC Drivers |
--------------------------
OS
---------------- PCI -----------------
Hardware + Firmware
----------------------------
| ISH Hardware/Firmware(FW) |
----------------------------
High level processing in above blocks
=====================================
Hardware Interface
------------------
The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
product and vendor IDs are changed from different generations of processors. So
the source code which enumerates drivers needs to update from generation to
generation.
Inter Processor Communication (IPC) driver
------------------------------------------
Location: drivers/hid/intel-ish-hid/ipc
The IPC message uses memory mapped I/O. The registers are defined in
hw-ish-regs.h.
IPC/FW message types
^^^^^^^^^^^^^^^^^^^^
There are two types of messages, one for management of link and another for
messages to and from transport layers.
TX and RX of Transport messages
...............................
A set of memory mapped register offers support of multi-byte messages TX and
RX (e.g. IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
internal queues to sequence messages and send them in order to the firmware.
Optionally the caller can register handler to get notification of completion.
A doorbell mechanism is used in messaging to trigger processing in host and
client firmware side. When ISH interrupt handler is called, the ISH2HOST
doorbell register is used by host drivers to determine that the interrupt
is for ISH.
Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
register has the following format::
Bits 0..6: fragment length (7 bits are used)
Bits 10..13: encapsulated protocol
Bits 16..19: management command (for IPC management protocol)
Bit 31: doorbell trigger (signal H/W interrupt to the other side)
Other bits are reserved, should be 0.
Transport layer interface
^^^^^^^^^^^^^^^^^^^^^^^^^
To abstract HW level IPC communication, a set of callbacks is registered.
The transport layer uses them to send and receive messages.
Refer to struct ishtp_hw_ops for callbacks.
ISH Transport layer
-------------------
Location: drivers/hid/intel-ish-hid/ishtp/
A Generic Transport Layer
^^^^^^^^^^^^^^^^^^^^^^^^^
The transport layer is a bi-directional protocol, which defines:
- Set of commands to start, stop, connect, disconnect and flow control
(see ishtp/hbm.h for details)
- A flow control mechanism to avoid buffer overflows
This protocol resembles bus messages described in the following document:
http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
Connection and Flow Control Mechanism
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Each FW client and a protocol is identified by a UUID. In order to communicate
to a FW client, a connection must be established using connect request and
response bus messages. If successful, a pair (host_client_id and fw_client_id)
will identify the connection.
Once connection is established, peers send each other flow control bus messages
independently. Every peer may send a message only if it has received a
flow-control credit before. Once it has sent a message, it may not send another one
before receiving the next flow control credit.
Either side can send disconnect request bus message to end communication. Also
the link will be dropped if major FW reset occurs.
Peer to Peer data transfer
^^^^^^^^^^^^^^^^^^^^^^^^^^
Peer to Peer data transfer can happen with or without using DMA. Depending on
the sensor bandwidth requirement DMA can be enabled by using module parameter
ishtp_use_dma under intel_ishtp.
Each side (host and FW) manages its DMA transfer memory independently. When an
ISHTP client from either host or FW side wants to send something, it decides
whether to send over IPC or over DMA; for each transfer the decision is
independent. The sending side sends DMA_XFER message when the message is in
the respective host buffer (TX when host client sends, RX when FW client
sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
the sender that the memory region for that message may be reused.
DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
Additionally to DMA address communication, this sequence checks capabilities:
if the host doesn't support DMA, then it won't send DMA allocation, so FW can't
send DMA; if FW doesn't support DMA then it won't respond with
DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
that it already did DMA and the message resides at host. Thus, DMA_XFER
and DMA_XFER_ACK act as ownership indicators.
At initial state all outgoing memory belongs to the sender (TX to host, RX to
FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
need not wait for previous DMA_XFER to be ack'ed, and may send another message
as long as remaining continuous memory in its ownership is enough.
In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
(up to IPC MTU), thus allowing for interrupt throttling.
Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
fragments and via IPC otherwise.
Ring Buffers
^^^^^^^^^^^^
When a client initiates a connection, a ring of RX and TX buffers is allocated.
The size of ring can be specified by the client. HID client sets 16 and 32 for
TX and RX buffers respectively. On send request from client, the data to be
sent is copied to one of the send ring buffer and scheduled to be sent using
bus message protocol. These buffers are required because the FW may have not
have processed the last message and may not have enough flow control credits
to send. Same thing holds true on receive side and flow control is required.
Host Enumeration
^^^^^^^^^^^^^^^^
The host enumeration bus command allows discovery of clients present in the FW.
There can be multiple sensor clients and clients for calibration function.
To ease implementation and allow independent drivers to handle each client,
this transport layer takes advantage of Linux Bus driver model. Each
client is registered as device on the transport bus (ishtp bus).
Enumeration sequence of messages:
- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
- FW responds with HOST_START_RES_CMD
- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
client IDs
- For each FW ID found in that bitmap host sends
HOST_CLIENT_PROPERTIES_REQ_CMD
- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
max ISHTP message size, etc.
- Once host received properties for that last discovered client, it considers
ISHTP device fully functional (and allocates DMA buffers)
HID over ISH Client
-------------------
Location: drivers/hid/intel-ish-hid
The ISHTP client driver is responsible for:
- enumerate HID devices under FW ISH client
- Get Report descriptor
- Register with HID core as a LL driver
- Process Get/Set feature request
- Get input reports
HID Sensor Hub MFD and IIO sensor drivers
-----------------------------------------
The functionality in these drivers is the same as an external sensor hub.
Refer to
Documentation/hid/hid-sensor.rst for HID sensor
Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space.
End to End HID transport Sequence Diagram
-----------------------------------------
::
HID-ISH-CLN ISHTP IPC HW
| | | |
| | |-----WAKE UP------------------>|
| | | |
| | |-----HOST READY--------------->|
| | | |
| | |<----MNG_RESET_NOTIFY_ACK----- |
| | | |
| |<----ISHTP_START------ | |
| | | |
| |<-----------------HOST_START_RES_CMD-------------------|
| | | |
| |------------------QUERY_SUBSCRIBER-------------------->|
| | | |
| |------------------HOST_ENUM_REQ_CMD------------------->|
| | | |
| |<-----------------HOST_ENUM_RES_CMD--------------------|
| | | |
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
| | | |
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
| Create new device on in ishtp bus | |
| | | |
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
| | | |
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
| Create new device on in ishtp bus | |
| | | |
| |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
| | | |
probed()
|----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
| | | |
| |<----------------CLIENT_CONNECT_RES_CMD----------------|
| | | |
|register event callback | | |
| | | |
|ishtp_cl_send(
HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
| | | |
| | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
| | | |
|<--ENUM_DEVICE RSP------| | |
| | | |
for each enumerated device
|ishtp_cl_send(
HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW----- >|
| | | |
...Response
| | | |
for each enumerated device
|ishtp_cl_send(
HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|
| | | |
| | | |
hid_allocate_device
| | | |
hid_add_device | | |
| | | |
ISH Firmware Loading from Host Flow
-----------------------------------
Starting from the Lunar Lake generation, the ISH firmware has been divided into two components for better space optimization and increased flexibility. These components include a bootloader that is integrated into the BIOS, and a main firmware that is stored within the operating system's file system.
The process works as follows:
- Initially, the ISHTP driver sends a command, HOST_START_REQ_CMD, to the ISH bootloader. In response, the bootloader sends back a HOST_START_RES_CMD. This response includes the ISHTP_SUPPORT_CAP_LOADER bit. Subsequently, the ISHTP driver checks if this bit is set. If it is, the firmware loading process from the host begins.
- During this process, the ISHTP driver first invokes the request_firmware() function, followed by sending a LOADER_CMD_XFER_QUERY command. Upon receiving a response from the bootloader, the ISHTP driver sends a LOADER_CMD_XFER_FRAGMENT command. After receiving another response, the ISHTP driver sends a LOADER_CMD_START command. The bootloader responds and then proceeds to the Main Firmware.
- After the process concludes, the ISHTP driver calls the release_firmware() function.
For more detailed information, please refer to the flow descriptions provided below:
::
+---------------+ +-----------------+
| ISHTP Driver | | ISH Bootloader |
+---------------+ +-----------------+
| |
|~~~Send HOST_START_REQ_CMD~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send HOST_START_RES_CMD(Includes ISHTP_SUPPORT_CAP_LOADER bit)----|
| |
****************************************************************************************
* if ISHTP_SUPPORT_CAP_LOADER bit is set *
****************************************************************************************
| |
|~~~start loading firmware from host process~~~+ |
| | |
|<---------------------------------------------+ |
| |
--------------------------- |
| Call request_firmware() | |
--------------------------- |
| |
|~~~Send LOADER_CMD_XFER_QUERY~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
|~~~Send LOADER_CMD_XFER_FRAGMENT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
|~~~Send LOADER_CMD_START~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
| |~~~Jump to Main Firmware~~~+
| | |
| |<--------------------------+
| |
--------------------------- |
| Call release_firmware() | |
--------------------------- |
| |
****************************************************************************************
* end if *
****************************************************************************************
| |
+---------------+ +-----------------+
| ISHTP Driver | | ISH Bootloader |
+---------------+ +-----------------+
Vendor Custom Firmware Loading
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The firmware running inside ISH can be provided by Intel or developed by vendors using the Firmware Development Kit (FDK) provided by Intel.
Intel will upstream the Intel-built firmware to the ``linux-firmware.git`` repository, located under the path ``intel/ish/``. For the Lunar Lake platform, the Intel-built ISH firmware will be named ``ish_lnlm.bin``.
Vendors who wish to upstream their custom firmware should follow these guidelines for naming their firmware files:
- The firmware filename should use one of the following patterns:
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin``
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin``
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin``
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin``
- ``${intel_plat_gen}`` indicates the Intel platform generation (e.g., ``lnlm`` for Lunar Lake) and must not exceed 8 characters in length.
- ``${SYS_VENDOR_CRC32}`` is the CRC32 checksum of the ``sys_vendor`` value from the DMI field ``DMI_SYS_VENDOR``.
- ``${PRODUCT_NAME_CRC32}`` is the CRC32 checksum of the ``product_name`` value from the DMI field ``DMI_PRODUCT_NAME``.
- ``${PRODUCT_SKU_CRC32}`` is the CRC32 checksum of the ``product_sku`` value from the DMI field ``DMI_PRODUCT_SKU``.
During system boot, the ISH Linux driver will attempt to load the firmware in the following order, prioritizing custom firmware with more precise matching patterns:
1. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin``
2. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin``
3. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin``
4. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin``
5. ``intel/ish/ish_${intel_plat_gen}.bin``
The driver will load the first matching firmware and skip the rest. If no matching firmware is found, it will proceed to the next pattern in the specified order. If all searches fail, the default Intel firmware, listed last in the order above, will be loaded.
ISH Debugging
-------------
To debug ISH, event tracing mechanism is used. To enable debug logs::
echo 1 > /sys/kernel/tracing/events/intel_ish/enable
cat /sys/kernel/tracing/trace
ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
-------------------------------------------------
::
root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
/sys/bus/iio/devices/
├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
│ ├── buffer
│ │ ├── enable
│ │ ├── length
│ │ └── watermark
...
│ ├── in_accel_hysteresis
│ ├── in_accel_offset
│ ├── in_accel_sampling_frequency
│ ├── in_accel_scale
│ ├── in_accel_x_raw
│ ├── in_accel_y_raw
│ ├── in_accel_z_raw
│ ├── name
│ ├── scan_elements
│ │ ├── in_accel_x_en
│ │ ├── in_accel_x_index
│ │ ├── in_accel_x_type
│ │ ├── in_accel_y_en
│ │ ├── in_accel_y_index
│ │ ├── in_accel_y_type
│ │ ├── in_accel_z_en
│ │ ├── in_accel_z_index
│ │ └── in_accel_z_type
...
│ │ ├── devices
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_intensity_both_raw
│ │ │ │ ├── in_intensity_hysteresis
│ │ │ │ ├── in_intensity_offset
│ │ │ │ ├── in_intensity_sampling_frequency
│ │ │ │ ├── in_intensity_scale
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_intensity_both_en
│ │ │ │ │ ├── in_intensity_both_index
│ │ │ │ │ └── in_intensity_both_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_magn_hysteresis
│ │ │ │ ├── in_magn_offset
│ │ │ │ ├── in_magn_sampling_frequency
│ │ │ │ ├── in_magn_scale
│ │ │ │ ├── in_magn_x_raw
│ │ │ │ ├── in_magn_y_raw
│ │ │ │ ├── in_magn_z_raw
│ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
│ │ │ │ ├── in_rot_hysteresis
│ │ │ │ ├── in_rot_offset
│ │ │ │ ├── in_rot_sampling_frequency
│ │ │ │ ├── in_rot_scale
│ │ │ │ ├── name
...
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_magn_x_en
│ │ │ │ │ ├── in_magn_x_index
│ │ │ │ │ ├── in_magn_x_type
│ │ │ │ │ ├── in_magn_y_en
│ │ │ │ │ ├── in_magn_y_index
│ │ │ │ │ ├── in_magn_y_type
│ │ │ │ │ ├── in_magn_z_en
│ │ │ │ │ ├── in_magn_z_index
│ │ │ │ │ ├── in_magn_z_type
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
│ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_anglvel_hysteresis
│ │ │ │ ├── in_anglvel_offset
│ │ │ │ ├── in_anglvel_sampling_frequency
│ │ │ │ ├── in_anglvel_scale
│ │ │ │ ├── in_anglvel_x_raw
│ │ │ │ ├── in_anglvel_y_raw
│ │ │ │ ├── in_anglvel_z_raw
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_anglvel_x_en
│ │ │ │ │ ├── in_anglvel_x_index
│ │ │ │ │ ├── in_anglvel_x_type
│ │ │ │ │ ├── in_anglvel_y_en
│ │ │ │ │ ├── in_anglvel_y_index
│ │ │ │ │ ├── in_anglvel_y_type
│ │ │ │ │ ├── in_anglvel_z_en
│ │ │ │ │ ├── in_anglvel_z_index
│ │ │ │ │ └── in_anglvel_z_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_anglvel_hysteresis
│ │ │ │ ├── in_anglvel_offset
│ │ │ │ ├── in_anglvel_sampling_frequency
│ │ │ │ ├── in_anglvel_scale
│ │ │ │ ├── in_anglvel_x_raw
│ │ │ │ ├── in_anglvel_y_raw
│ │ │ │ ├── in_anglvel_z_raw
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_anglvel_x_en
│ │ │ │ │ ├── in_anglvel_x_index
│ │ │ │ │ ├── in_anglvel_x_type
│ │ │ │ │ ├── in_anglvel_y_en
│ │ │ │ │ ├── in_anglvel_y_index
│ │ │ │ │ ├── in_anglvel_y_type
│ │ │ │ │ ├── in_anglvel_z_en
│ │ │ │ │ ├── in_anglvel_z_index
│ │ │ │ │ └── in_anglvel_z_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
통합 Sensor Hub의 목적과 USB 대응 모델
1-60Sensor hub는 sensor polling과 algorithm 처리를 전용 저전력 co-processor로 넘깁니다. 그 결과 core processor가 더 자주 low-power mode에 들어갈 수 있어 battery life가 늘어납니다.
여러 vendor가 HID Sensor usage table을 따르는 외장 sensor hub를 공급하며, tablet, 2-in-1 convertible laptop, embedded product에서 사용됩니다. Linux는 Linux 3.9부터 이러한 외장 hub를 지원합니다.
Intel은 Cherry Trail부터 SoC에 Integrated Sensor Hub(ISH)를 넣었고, 이후 여러 세대의 CPU package에서 지원했습니다. 이미 많은 상용 장치에 ISH가 탑재되어 있습니다. ISH도 HID sensor specification을 따르지만 통신 transport protocol이 다릅니다. 외장 sensor hub는 주로 HID over I2C 또는 USB를 쓰는 반면, ISH는 I2C와 USB 어느 쪽도 사용하지 않습니다.
ISH는 빠른 통신을 위해 usbhid와 비슷한 계층 모델을 사용합니다. `USB HID`에 `ISH HID`, `USB protocol`에 `ISH Transport`, `EHCI/XHCI`에 `ISH IPC`, `Host controller`에 `ISH processor`, `USB End points`에 `ISH Clients`가 각각 대응합니다. 양쪽 controller 계층은 PCI로 host에 연결됩니다.
USB protocol이 device enumeration, link management, user data encapsulation을 제공하듯 ISH도 같은 종류의 서비스를 제공합니다. 다만 firmware에 구현된 ISH client application을 관리하고 통신하는 데 맞춘 매우 가벼운 protocol입니다.
ISH firmware 안에서는 여러 sensor management application을 동시에 실행할 수 있습니다. USB endpoint처럼 각 client로 message를 보내거나 client에서 받을 수 있으며 enumeration 과정에서 client를 식별합니다. Client는 단순 HID sensor application, sensor calibration application 또는 sensor firmware update application일 수 있습니다.
구현 모델에서도 ISH transport는 USB bus처럼 bus로 구현됩니다. ISH processor에서 실행되는 각 client application은 이 bus의 device로 등록됩니다. 각 device에 bind하는 ISH HID driver가 device type을 판별하고 HID core에 등록합니다.
원문의 비교 도식을 같은 역할끼리 정렬했습니다.
Firmware client가 Linux HID 계층에 나타나는 경로입니다.
=================================
Intel Integrated Sensor Hub (ISH)
=================================
A sensor hub enables the ability to offload sensor polling and algorithm
processing to a dedicated low power co-processor. This allows the core
processor to go into low power modes more often, resulting in increased
battery life.
There are many vendors providing external sensor hubs conforming to HID
Sensor usage tables. These may be found in tablets, 2-in-1 convertible laptops
and embedded products. Linux has had this support since Linux 3.9.
Intel® introduced integrated sensor hubs as a part of the SoC starting from
Cherry Trail and now supported on multiple generations of CPU packages. There
are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
These ISH also comply to HID sensor specification, but the difference is the
transport protocol used for communication. The current external sensor hubs
mainly use HID over I2C or USB. But ISH doesn't use either I2C or USB.
Overview
========
Using a analogy with a usbhid implementation, the ISH follows a similar model
for a very high speed communication::
----------------- ----------------------
| USB HID | --> | ISH HID |
----------------- ----------------------
----------------- ----------------------
| USB protocol | --> | ISH Transport |
----------------- ----------------------
----------------- ----------------------
| EHCI/XHCI | --> | ISH IPC |
----------------- ----------------------
PCI PCI
----------------- ----------------------
|Host controller| --> | ISH processor |
----------------- ----------------------
USB Link
----------------- ----------------------
| USB End points| --> | ISH Clients |
----------------- ----------------------
Like USB protocol provides a method for device enumeration, link management
and user data encapsulation, the ISH also provides similar services. But it is
very light weight tailored to manage and communicate with ISH client
applications implemented in the firmware.
The ISH allows multiple sensor management applications executing in the
firmware. Like USB endpoints the messaging can be to/from a client. As part of
enumeration process, these clients are identified. These clients can be simple
HID sensor applications, sensor calibration applications or sensor firmware
update applications.
The implementation model is similar, like USB bus, ISH transport is also
implemented as a bus. Each client application executing in the ISH processor
is registered as a device on this bus. The driver, which binds each device
(ISH HID driver) identifies the device type and registers with the HID core.
ISH software stack과 hardware interface
61-116구현 stack의 맨 위에는 user space application이 있고 IIO ABI를 통해 IIO Sensor Driver와 통신합니다. 그 아래로 IIO core, HID Sensor Hub MFD, HID Core, HID over ISH Client, ISH Transport(ISHTP), IPC Driver가 차례로 놓입니다. OS와 hardware·firmware의 경계는 PCI이며, 최하단에는 ISH Hardware/Firmware(FW)가 있습니다.
Host에서 ISH는 `Non-VGA unclassified PCI device`로 노출됩니다. PCI product ID와 vendor ID는 processor generation에 따라 달라지므로 driver를 enumerate하는 source code도 세대가 바뀔 때마다 갱신해야 합니다.
Inter Processor Communication(IPC) driver는 `drivers/hid/intel-ish-hid/ipc`에 있습니다. IPC message는 memory-mapped I/O를 사용하고 관련 register는 `hw-ish-regs.h`에 정의됩니다.
원문의 세로 block diagram을 userspace에서 hardware까지 정리했습니다.
ISH에서 userspace까지 data가 이동하는 계층입니다.
ISH Implementation: Block Diagram
=================================
::
---------------------------
| User Space Applications |
---------------------------
----------------IIO ABI----------------
--------------------------
| IIO Sensor Drivers |
--------------------------
--------------------------
| IIO core |
--------------------------
--------------------------
| HID Sensor Hub MFD |
--------------------------
--------------------------
| HID Core |
--------------------------
--------------------------
| HID over ISH Client |
--------------------------
--------------------------
| ISH Transport (ISHTP) |
--------------------------
--------------------------
| IPC Drivers |
--------------------------
OS
---------------- PCI -----------------
Hardware + Firmware
----------------------------
| ISH Hardware/Firmware(FW) |
----------------------------
High level processing in above blocks
=====================================
Hardware Interface
------------------
The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
product and vendor IDs are changed from different generations of processors. So
the source code which enumerates drivers needs to update from generation to
generation.
Inter Processor Communication (IPC) driver
------------------------------------------
Location: drivers/hid/intel-ish-hid/ipc
The IPC message uses memory mapped I/O. The registers are defined in
hw-ish-regs.h.
IPC message, doorbell과 ISHTP flow control
117-182IPC/FW message에는 두 종류가 있습니다. 하나는 link를 관리하는 message이고, 다른 하나는 transport layer로 오가는 data message입니다.
여러 byte의 transport message를 송수신하기 위해 `IPC_REG_ISH2HOST_MSG`, `IPC_REG_HOST2ISH_MSG` 같은 memory-mapped register 집합을 사용합니다. IPC layer는 internal queue로 message 순서를 유지하여 firmware에 전송하며, caller는 선택적으로 completion notification handler를 등록할 수 있습니다.
Message 처리를 host와 client firmware 쪽에서 시작시키는 데 doorbell mechanism을 씁니다. ISH interrupt handler가 호출되면 host driver는 ISH2HOST doorbell register를 확인해 그 interrupt가 ISH에서 온 것인지 판별합니다.
양쪽에는 각각 32개의 32-bit message register와 하나의 32-bit doorbell이 있습니다. Doorbell bit 0..6은 7-bit fragment length, 10..13은 encapsulated protocol, 16..19는 IPC management protocol의 management command, bit 31은 상대편에 hardware interrupt를 발생시키는 trigger입니다. 나머지 bit는 reserved이며 0이어야 합니다.
Hardware 수준 IPC를 추상화하기 위해 callback 집합을 등록하며 transport layer는 이 callback으로 message를 송수신합니다. Callback 정의는 `struct ishtp_hw_ops`를 참조합니다.
ISH transport layer는 `drivers/hid/intel-ish-hid/ishtp/`에 있습니다. 이 양방향 generic protocol은 start, stop, connect, disconnect, flow control command 집합과 buffer overflow를 막는 flow-control mechanism을 정의합니다. 자세한 command는 `ishtp/hbm.h`에 있으며, protocol 구조는 Intel DCMI 문서 Chapter 7의 Bus Message Layer와 비슷합니다.
각 FW client와 protocol은 UUID로 식별합니다. 통신하려면 connect request와 response bus message로 connection을 맺어야 하며, 성공하면 `(host_client_id, fw_client_id)` 쌍이 connection을 식별합니다.
Connection이 성립한 뒤 두 peer는 서로 독립적으로 flow-control bus message를 보냅니다. 각 peer는 미리 flow-control credit을 받은 경우에만 message 하나를 보낼 수 있고, 보낸 뒤에는 다음 credit을 받을 때까지 다른 message를 보낼 수 없습니다. 어느 쪽이든 disconnect request를 보내 통신을 끝낼 수 있으며 major FW reset이 발생해도 link가 끊깁니다.
Reserved bit는 항상 0으로 유지해야 합니다.
한 message마다 credit을 소비하는 흐름입니다.
IPC/FW message types
^^^^^^^^^^^^^^^^^^^^
There are two types of messages, one for management of link and another for
messages to and from transport layers.
TX and RX of Transport messages
...............................
A set of memory mapped register offers support of multi-byte messages TX and
RX (e.g. IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
internal queues to sequence messages and send them in order to the firmware.
Optionally the caller can register handler to get notification of completion.
A doorbell mechanism is used in messaging to trigger processing in host and
client firmware side. When ISH interrupt handler is called, the ISH2HOST
doorbell register is used by host drivers to determine that the interrupt
is for ISH.
Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
register has the following format::
Bits 0..6: fragment length (7 bits are used)
Bits 10..13: encapsulated protocol
Bits 16..19: management command (for IPC management protocol)
Bit 31: doorbell trigger (signal H/W interrupt to the other side)
Other bits are reserved, should be 0.
Transport layer interface
^^^^^^^^^^^^^^^^^^^^^^^^^
To abstract HW level IPC communication, a set of callbacks is registered.
The transport layer uses them to send and receive messages.
Refer to struct ishtp_hw_ops for callbacks.
ISH Transport layer
-------------------
Location: drivers/hid/intel-ish-hid/ishtp/
A Generic Transport Layer
^^^^^^^^^^^^^^^^^^^^^^^^^
The transport layer is a bi-directional protocol, which defines:
- Set of commands to start, stop, connect, disconnect and flow control
(see ishtp/hbm.h for details)
- A flow control mechanism to avoid buffer overflows
This protocol resembles bus messages described in the following document:
http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
Connection and Flow Control Mechanism
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Each FW client and a protocol is identified by a UUID. In order to communicate
to a FW client, a connection must be established using connect request and
response bus messages. If successful, a pair (host_client_id and fw_client_id)
will identify the connection.
Once connection is established, peers send each other flow control bus messages
independently. Every peer may send a message only if it has received a
flow-control credit before. Once it has sent a message, it may not send another one
before receiving the next flow control credit.
Either side can send disconnect request bus message to end communication. Also
the link will be dropped if major FW reset occurs.
Peer-to-peer DMA와 ring buffer
183-229Peer-to-peer data transfer는 DMA를 사용하거나 사용하지 않고 수행할 수 있습니다. Sensor bandwidth 요구에 따라 `intel_ishtp`의 module parameter `ishtp_use_dma`로 DMA를 활성화합니다.
Host와 FW는 각자 DMA transfer memory를 독립적으로 관리합니다. 어느 쪽의 ISHTP client든 전송할 때마다 IPC와 DMA 중 하나를 독립적으로 선택합니다. Sender는 message가 해당 host buffer에 있을 때 `DMA_XFER`를 보냅니다. Host client가 보낼 때는 TX buffer, FW client가 보낼 때는 RX buffer입니다. Recipient는 `DMA_XFER_ACK`로 응답하여 그 memory region을 sender가 다시 써도 된다고 알립니다.
DMA 초기화는 host가 RX buffer 정보를 포함한 `DMA_ALLOC_NOTIFY` bus message를 보내고 FW가 `DMA_ALLOC_NOTIFY_ACK`로 응답하면서 시작됩니다. 이 교환은 DMA address뿐 아니라 capability도 확인합니다. Host가 DMA를 지원하지 않으면 allocation message를 보내지 않아 FW가 DMA를 쓸 수 없습니다. FW가 지원하지 않으면 ACK하지 않으므로 host도 DMA transfer를 사용하지 않습니다.
여기서 ISH는 busmaster DMA controller입니다. Host가 `DMA_XFER`를 보내면 host에서 ISH로 DMA하라는 request이고, FW가 보내면 이미 DMA를 수행하여 message가 host에 있다는 뜻입니다. 따라서 `DMA_XFER`와 `DMA_XFER_ACK`는 memory ownership indicator로 작동합니다.
초기에는 모든 outgoing memory가 sender 소유입니다. Host의 TX는 host가, FW의 RX는 FW가 소유합니다. `DMA_XFER`가 ISHTP message를 담은 region의 ownership을 receiver로 넘기고, `DMA_XFER_ACK`가 sender에게 돌려줍니다. Sender가 소유한 연속 memory가 다음 message를 담기에 충분하면 이전 XFER의 ACK를 기다리지 않고 다음 message를 보낼 수 있습니다.
원칙적으로 IPC MTU까지 여러 `DMA_XFER`와 `DMA_XFER_ACK`를 한 번에 보내 interrupt를 줄일 수 있습니다. 현재 ISH FW는 ISHTP message가 IPC fragment 3개보다 크면 DMA를, 그렇지 않으면 IPC를 선택합니다.
Client가 connection을 시작하면 RX·TX buffer ring을 할당하며 ring size는 client가 지정할 수 있습니다. HID client는 TX 16개와 RX 32개를 사용합니다. Send request의 data는 send ring buffer 하나에 복사된 뒤 bus message protocol 전송 대상으로 schedule됩니다. FW가 이전 message를 아직 처리하지 않았거나 flow-control credit이 부족할 수 있으므로 이런 buffer가 필요합니다. Receive 쪽도 같은 이유로 buffer와 flow control이 필요합니다.
각 message가 memory 소유권에 미치는 영향을 정리했습니다.
Capability 협상부터 buffer 재사용까지의 순서입니다.
Peer to Peer data transfer
^^^^^^^^^^^^^^^^^^^^^^^^^^
Peer to Peer data transfer can happen with or without using DMA. Depending on
the sensor bandwidth requirement DMA can be enabled by using module parameter
ishtp_use_dma under intel_ishtp.
Each side (host and FW) manages its DMA transfer memory independently. When an
ISHTP client from either host or FW side wants to send something, it decides
whether to send over IPC or over DMA; for each transfer the decision is
independent. The sending side sends DMA_XFER message when the message is in
the respective host buffer (TX when host client sends, RX when FW client
sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
the sender that the memory region for that message may be reused.
DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
Additionally to DMA address communication, this sequence checks capabilities:
if the host doesn't support DMA, then it won't send DMA allocation, so FW can't
send DMA; if FW doesn't support DMA then it won't respond with
DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
that it already did DMA and the message resides at host. Thus, DMA_XFER
and DMA_XFER_ACK act as ownership indicators.
At initial state all outgoing memory belongs to the sender (TX to host, RX to
FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
need not wait for previous DMA_XFER to be ack'ed, and may send another message
as long as remaining continuous memory in its ownership is enough.
In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
(up to IPC MTU), thus allowing for interrupt throttling.
Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
fragments and via IPC otherwise.
Ring Buffers
^^^^^^^^^^^^
When a client initiates a connection, a ring of RX and TX buffers is allocated.
The size of ring can be specified by the client. HID client sets 16 and 32 for
TX and RX buffers respectively. On send request from client, the data to be
sent is copied to one of the send ring buffer and scheduled to be sent using
bus message protocol. These buffers are required because the FW may have not
have processed the last message and may not have enough flow control credits
to send. Same thing holds true on receive side and flow control is required.
Host enumeration과 HID over ISH client
230-275Host enumeration bus command는 FW에 존재하는 client를 발견합니다. 여러 sensor client와 calibration 기능 client가 함께 존재할 수 있습니다.
각 client를 독립 driver가 쉽게 처리하도록 transport layer는 Linux Bus driver model을 이용합니다. 발견한 client마다 ISHTP bus의 device로 등록합니다.
Enumeration은 host가 ISHTP layer 준비를 알리는 `HOST_START_REQ_CMD`를 보내면서 시작합니다. FW가 `HOST_START_RES_CMD`로 응답하면 host는 FW client 열거를 요청하는 `HOST_ENUM_REQ_CMD`를 보내고, FW는 사용 가능한 FW client ID bitmap을 담은 `HOST_ENUM_RES_CMD`로 응답합니다.
Host는 bitmap에서 찾은 FW ID마다 `HOST_CLIENT_PROPERTIES_REQ_CMD`를 보냅니다. FW의 `HOST_CLIENT_PROPERTIES_RES_CMD`에는 UUID, 최대 ISHTP message size 등의 property가 들어 있습니다. 마지막 client의 property까지 받으면 host는 ISHTP device가 완전히 동작한다고 판단하고 DMA buffer를 할당합니다.
HID over ISH client driver의 위치는 `drivers/hid/intel-ish-hid`입니다. 이 driver는 FW ISH client 아래의 HID device를 열거하고 Report descriptor를 가져오며, HID core에 low-level driver로 등록합니다. 또한 Get/Set feature request와 input report 수신을 처리합니다.
HID Sensor Hub MFD와 IIO sensor driver의 기능은 외장 sensor hub에서와 같습니다. HID sensor 설명은 `Documentation/hid/hid-sensor.rst`, userspace용 IIO ABI는 `Documentation/ABI/testing/sysfs-bus-iio`를 참조합니다.
Firmware client가 bus device가 될 때까지의 command입니다.
마지막 property 응답 뒤 transport가 정상 동작합니다.
Host Enumeration
^^^^^^^^^^^^^^^^
The host enumeration bus command allows discovery of clients present in the FW.
There can be multiple sensor clients and clients for calibration function.
To ease implementation and allow independent drivers to handle each client,
this transport layer takes advantage of Linux Bus driver model. Each
client is registered as device on the transport bus (ishtp bus).
Enumeration sequence of messages:
- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
- FW responds with HOST_START_RES_CMD
- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
client IDs
- For each FW ID found in that bitmap host sends
HOST_CLIENT_PROPERTIES_REQ_CMD
- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
max ISHTP message size, etc.
- Once host received properties for that last discovered client, it considers
ISHTP device fully functional (and allocates DMA buffers)
HID over ISH Client
-------------------
Location: drivers/hid/intel-ish-hid
The ISHTP client driver is responsible for:
- enumerate HID devices under FW ISH client
- Get Report descriptor
- Register with HID core as a LL driver
- Process Get/Set feature request
- Get input reports
HID Sensor Hub MFD and IIO sensor drivers
-----------------------------------------
The functionality in these drivers is the same as an external sensor hub.
Refer to
Documentation/hid/hid-sensor.rst for HID sensor
Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space.
End-to-end HID transport sequence
276-340전체 sequence에는 HID-ISH-CLN, ISHTP, IPC, HW 네 참여자가 있습니다. 먼저 IPC가 HW에 `WAKE UP`과 `HOST READY`를 보내고, HW는 `MNG_RESET_NOTIFY_ACK`를 돌려줍니다. IPC는 ISHTP에 `ISHTP_START`를 알리고, HW에서 ISHTP로 `HOST_START_RES_CMD`가 도착합니다.
ISHTP는 HW에 `QUERY_SUBSCRIBER`와 `HOST_ENUM_REQ_CMD`를 보내고 `HOST_ENUM_RES_CMD`를 받습니다. 이어 `HOST_CLIENT_PROPERTIES_REQ_CMD`와 `HOST_CLIENT_PROPERTIES_RES_CMD`를 client마다 반복합니다. 각 property 응답 뒤 ishtp bus에 새 device를 만들고 마지막 client까지 이 과정을 계속합니다.
생성된 HID-ISH client driver의 `probed()`가 실행되면 `ishtp_cl_connect`가 ISHTP에 연결을 요청합니다. ISHTP는 HW에 `CLIENT_CONNECT_REQ_CMD`를 보내고 `CLIENT_CONNECT_RES_CMD`를 받은 뒤 client가 event callback을 등록합니다.
Client는 `ishtp_cl_send(HOSTIF_DM_ENUM_DEVICES)`로 firmware 아래 HID device를 열거합니다. ISHTP는 `ishtp_msg_hdr` 구조체를 채워 hardware에 쓰고, HW interrupt `IRQ(IPC_PROTOCOL_ISHTP)`가 IPC에 전달된 다음 `ENUM_DEVICE RSP`가 client로 돌아옵니다.
열거된 각 device에 대해 client가 `HOSTIF_GET_HID_DESCRIPTOR`를 보내 HID descriptor와 response를 받고, 다시 `HOSTIF_GET_REPORT_DESCRIPTOR`를 보내 report descriptor를 받습니다. 필요한 descriptor를 모두 확보하면 `hid_allocate_device`와 `hid_add_device`를 실행해 Linux HID device를 완성합니다.
원문의 네 열 sequence diagram을 단계별로 정리했습니다.
Hardware wake-up에서 HID core 등록까지 이어집니다.
End to End HID transport Sequence Diagram
-----------------------------------------
::
HID-ISH-CLN ISHTP IPC HW
| | | |
| | |-----WAKE UP------------------>|
| | | |
| | |-----HOST READY--------------->|
| | | |
| | |<----MNG_RESET_NOTIFY_ACK----- |
| | | |
| |<----ISHTP_START------ | |
| | | |
| |<-----------------HOST_START_RES_CMD-------------------|
| | | |
| |------------------QUERY_SUBSCRIBER-------------------->|
| | | |
| |------------------HOST_ENUM_REQ_CMD------------------->|
| | | |
| |<-----------------HOST_ENUM_RES_CMD--------------------|
| | | |
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
| | | |
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
| Create new device on in ishtp bus | |
| | | |
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
| | | |
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
| Create new device on in ishtp bus | |
| | | |
| |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
| | | |
probed()
|----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
| | | |
| |<----------------CLIENT_CONNECT_RES_CMD----------------|
| | | |
|register event callback | | |
| | | |
|ishtp_cl_send(
HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
| | | |
| | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
| | | |
|<--ENUM_DEVICE RSP------| | |
| | | |
for each enumerated device
|ishtp_cl_send(
HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW----- >|
| | | |
...Response
| | | |
for each enumerated device
|ishtp_cl_send(
HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|
| | | |
| | | |
hid_allocate_device
| | | |
hid_add_device | | |
| | | |
Lunar Lake 이후 host firmware loading
341-406Lunar Lake generation부터 공간 최적화와 유연성을 높이기 위해 ISH firmware를 두 component로 나눴습니다. Bootloader는 BIOS에 통합되고 main firmware는 operating system file system에 저장됩니다.
먼저 ISHTP driver가 ISH bootloader에 `HOST_START_REQ_CMD`를 보냅니다. Bootloader의 `HOST_START_RES_CMD`에는 `ISHTP_SUPPORT_CAP_LOADER` bit가 들어 있습니다. Driver가 이 bit의 설정을 확인하면 host에서 firmware를 적재하는 절차를 시작합니다.
Driver는 먼저 `request_firmware()`를 호출하고 `LOADER_CMD_XFER_QUERY`를 보냅니다. Bootloader response를 받은 뒤 `LOADER_CMD_XFER_FRAGMENT`를 전송하고 다시 response를 기다립니다. 이어 `LOADER_CMD_START`를 보내고 응답을 받으면 bootloader가 main firmware로 jump합니다.
적재 절차가 끝나면 ISHTP driver는 `release_firmware()`를 호출합니다. `ISHTP_SUPPORT_CAP_LOADER` bit가 설정되지 않은 경우 이 host loading block 전체를 수행하지 않습니다.
Bootloader와 ISHTP driver가 교환하는 순서입니다.
Capability가 있을 때만 점선 안의 적재 절차를 수행합니다.
ISH Firmware Loading from Host Flow
-----------------------------------
Starting from the Lunar Lake generation, the ISH firmware has been divided into two components for better space optimization and increased flexibility. These components include a bootloader that is integrated into the BIOS, and a main firmware that is stored within the operating system's file system.
The process works as follows:
- Initially, the ISHTP driver sends a command, HOST_START_REQ_CMD, to the ISH bootloader. In response, the bootloader sends back a HOST_START_RES_CMD. This response includes the ISHTP_SUPPORT_CAP_LOADER bit. Subsequently, the ISHTP driver checks if this bit is set. If it is, the firmware loading process from the host begins.
- During this process, the ISHTP driver first invokes the request_firmware() function, followed by sending a LOADER_CMD_XFER_QUERY command. Upon receiving a response from the bootloader, the ISHTP driver sends a LOADER_CMD_XFER_FRAGMENT command. After receiving another response, the ISHTP driver sends a LOADER_CMD_START command. The bootloader responds and then proceeds to the Main Firmware.
- After the process concludes, the ISHTP driver calls the release_firmware() function.
For more detailed information, please refer to the flow descriptions provided below:
::
+---------------+ +-----------------+
| ISHTP Driver | | ISH Bootloader |
+---------------+ +-----------------+
| |
|~~~Send HOST_START_REQ_CMD~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send HOST_START_RES_CMD(Includes ISHTP_SUPPORT_CAP_LOADER bit)----|
| |
****************************************************************************************
* if ISHTP_SUPPORT_CAP_LOADER bit is set *
****************************************************************************************
| |
|~~~start loading firmware from host process~~~+ |
| | |
|<---------------------------------------------+ |
| |
--------------------------- |
| Call request_firmware() | |
--------------------------- |
| |
|~~~Send LOADER_CMD_XFER_QUERY~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
|~~~Send LOADER_CMD_XFER_FRAGMENT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
|~~~Send LOADER_CMD_START~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|
| |
|<--Send response-----------------------------------------------------|
| |
| |~~~Jump to Main Firmware~~~+
| | |
| |<--------------------------+
| |
--------------------------- |
| Call release_firmware() | |
--------------------------- |
| |
****************************************************************************************
* end if *
****************************************************************************************
| |
+---------------+ +-----------------+
| ISHTP Driver | | ISH Bootloader |
+---------------+ +-----------------+
Vendor custom firmware 이름과 검색 우선순위
407-435ISH에서 실행되는 firmware는 Intel이 제공하거나 vendor가 Intel Firmware Development Kit(FDK)로 개발할 수 있습니다. Intel-built firmware는 `linux-firmware.git` repository의 `intel/ish/` 아래에 upstream됩니다. Lunar Lake용 Intel firmware 이름은 `ish_lnlm.bin`입니다.
Vendor custom firmware filename은 네 pattern 중 하나를 사용해야 합니다. 가장 구체적인 형식은 `ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin`입니다. 그 밖에 product SKU만 포함한 `ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin`, product name만 포함한 `ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin`, system vendor만 포함한 `ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin`을 사용할 수 있습니다.
`${intel_plat_gen}`은 Intel platform generation을 뜻하며 Lunar Lake의 `lnlm`처럼 최대 8자입니다. `${SYS_VENDOR_CRC32}`는 DMI field `DMI_SYS_VENDOR`의 `sys_vendor`, `${PRODUCT_NAME_CRC32}`는 `DMI_PRODUCT_NAME`의 `product_name`, `${PRODUCT_SKU_CRC32}`는 `DMI_PRODUCT_SKU`의 `product_sku`에 대한 CRC32 checksum입니다.
Boot 중 driver는 가장 정밀한 custom match부터 차례로 검색합니다. 첫 일치 firmware를 적재하고 나머지는 건너뜁니다. 일치하지 않으면 다음 pattern으로 넘어가며 custom search가 모두 실패하면 마지막 기본 Intel firmware를 사용합니다.
경로는 모두 `intel/ish/` 아래이며 첫 일치 항목을 사용합니다.
구체적인 DMI match에서 기본 image 쪽으로 완화합니다.
Vendor Custom Firmware Loading
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The firmware running inside ISH can be provided by Intel or developed by vendors using the Firmware Development Kit (FDK) provided by Intel.
Intel will upstream the Intel-built firmware to the ``linux-firmware.git`` repository, located under the path ``intel/ish/``. For the Lunar Lake platform, the Intel-built ISH firmware will be named ``ish_lnlm.bin``.
Vendors who wish to upstream their custom firmware should follow these guidelines for naming their firmware files:
- The firmware filename should use one of the following patterns:
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin``
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin``
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin``
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin``
- ``${intel_plat_gen}`` indicates the Intel platform generation (e.g., ``lnlm`` for Lunar Lake) and must not exceed 8 characters in length.
- ``${SYS_VENDOR_CRC32}`` is the CRC32 checksum of the ``sys_vendor`` value from the DMI field ``DMI_SYS_VENDOR``.
- ``${PRODUCT_NAME_CRC32}`` is the CRC32 checksum of the ``product_name`` value from the DMI field ``DMI_PRODUCT_NAME``.
- ``${PRODUCT_SKU_CRC32}`` is the CRC32 checksum of the ``product_sku`` value from the DMI field ``DMI_PRODUCT_SKU``.
During system boot, the ISH Linux driver will attempt to load the firmware in the following order, prioritizing custom firmware with more precise matching patterns:
1. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin``
2. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin``
3. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin``
4. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin``
5. ``intel/ish/ish_${intel_plat_gen}.bin``
The driver will load the first matching firmware and skip the rest. If no matching firmware is found, it will proceed to the next pattern in the specified order. If all searches fail, the default Intel firmware, listed last in the order above, will be loaded.
ISH event tracing
436-443ISH debugging에는 event tracing mechanism을 사용합니다. 먼저 `echo 1 > /sys/kernel/tracing/events/intel_ish/enable`로 `intel_ish` event를 활성화한 뒤 `cat /sys/kernel/tracing/trace`로 수집된 trace를 읽습니다.
Enable node와 trace buffer를 구분합니다.
Event를 켠 뒤 재현하여 trace를 수집합니다.
ISH Debugging
-------------
To debug ISH, event tracing mechanism is used. To enable debug logs::
echo 1 > /sys/kernel/tracing/events/intel_ish/enable
cat /sys/kernel/tracing/trace
Lenovo ThinkPad Yoga 260 IIO sysfs 예제
444-581Lenovo ThinkPad Yoga 260의 예제는 `tree -l /sys/bus/iio/devices/` 출력으로 ISH sensor가 IIO device와 channel attribute로 노출되는 모습을 보여 줍니다. `iio:device0`은 `../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0`을 가리킵니다.
각 buffered IIO device에는 보통 `buffer/enable`, `buffer/length`, `buffer/watermark`가 있습니다. `scan_elements` 아래의 `_en`, `_index`, `_type` attribute는 channel을 scan에 포함할지, buffer에서의 index가 무엇인지, binary type과 layout이 무엇인지 나타냅니다. `trigger/current_trigger`는 현재 sample trigger를 가리킵니다.
Accelerometer는 `in_accel_hysteresis`, `in_accel_offset`, `in_accel_sampling_frequency`, `in_accel_scale`과 x·y·z의 `in_accel_*_raw`를 제공합니다. Scan element에도 x·y·z 각각의 enable, index, type이 있습니다.
Intensity sensor는 `in_intensity_both_raw`와 hysteresis, offset, sampling frequency, scale을 제공합니다. 단일 `both` channel에 대응하는 scan element의 enable, index, type과 current trigger도 함께 노출됩니다.
Magnetometer device는 `in_magn_x_raw`, `in_magn_y_raw`, `in_magn_z_raw`와 공통 hysteresis, offset, sampling frequency, scale을 제공합니다. 또한 tilt-compensated magnetic north rotation 값인 `in_rot_from_north_magnetic_tilt_comp_raw`와 rotation의 hysteresis, offset, sampling frequency, scale을 함께 제공합니다. Scan element에는 세 magnetic axis와 tilt-compensated rotation channel이 모두 들어갑니다.
Angular velocity device는 `in_anglvel_x_raw`, `in_anglvel_y_raw`, `in_anglvel_z_raw` 및 hysteresis, offset, sampling frequency, scale을 제공합니다. 원문 tree에는 같은 angular-velocity 형태의 device가 두 묶음 나타나며, 두 묶음 모두 x·y·z scan enable, index, type과 current trigger 구조를 가집니다.
긴 tree 출력을 sensor별 interface로 정리했습니다.
예제 tree에서 반복되는 attribute의 일반적인 사용 흐름입니다.
ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
-------------------------------------------------
::
root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
/sys/bus/iio/devices/
├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
│ ├── buffer
│ │ ├── enable
│ │ ├── length
│ │ └── watermark
...
│ ├── in_accel_hysteresis
│ ├── in_accel_offset
│ ├── in_accel_sampling_frequency
│ ├── in_accel_scale
│ ├── in_accel_x_raw
│ ├── in_accel_y_raw
│ ├── in_accel_z_raw
│ ├── name
│ ├── scan_elements
│ │ ├── in_accel_x_en
│ │ ├── in_accel_x_index
│ │ ├── in_accel_x_type
│ │ ├── in_accel_y_en
│ │ ├── in_accel_y_index
│ │ ├── in_accel_y_type
│ │ ├── in_accel_z_en
│ │ ├── in_accel_z_index
│ │ └── in_accel_z_type
...
│ │ ├── devices
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_intensity_both_raw
│ │ │ │ ├── in_intensity_hysteresis
│ │ │ │ ├── in_intensity_offset
│ │ │ │ ├── in_intensity_sampling_frequency
│ │ │ │ ├── in_intensity_scale
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_intensity_both_en
│ │ │ │ │ ├── in_intensity_both_index
│ │ │ │ │ └── in_intensity_both_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_magn_hysteresis
│ │ │ │ ├── in_magn_offset
│ │ │ │ ├── in_magn_sampling_frequency
│ │ │ │ ├── in_magn_scale
│ │ │ │ ├── in_magn_x_raw
│ │ │ │ ├── in_magn_y_raw
│ │ │ │ ├── in_magn_z_raw
│ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
│ │ │ │ ├── in_rot_hysteresis
│ │ │ │ ├── in_rot_offset
│ │ │ │ ├── in_rot_sampling_frequency
│ │ │ │ ├── in_rot_scale
│ │ │ │ ├── name
...
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_magn_x_en
│ │ │ │ │ ├── in_magn_x_index
│ │ │ │ │ ├── in_magn_x_type
│ │ │ │ │ ├── in_magn_y_en
│ │ │ │ │ ├── in_magn_y_index
│ │ │ │ │ ├── in_magn_y_type
│ │ │ │ │ ├── in_magn_z_en
│ │ │ │ │ ├── in_magn_z_index
│ │ │ │ │ ├── in_magn_z_type
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
│ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_anglvel_hysteresis
│ │ │ │ ├── in_anglvel_offset
│ │ │ │ ├── in_anglvel_sampling_frequency
│ │ │ │ ├── in_anglvel_scale
│ │ │ │ ├── in_anglvel_x_raw
│ │ │ │ ├── in_anglvel_y_raw
│ │ │ │ ├── in_anglvel_z_raw
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_anglvel_x_en
│ │ │ │ │ ├── in_anglvel_x_index
│ │ │ │ │ ├── in_anglvel_x_type
│ │ │ │ │ ├── in_anglvel_y_en
│ │ │ │ │ ├── in_anglvel_y_index
│ │ │ │ │ ├── in_anglvel_y_type
│ │ │ │ │ ├── in_anglvel_z_en
│ │ │ │ │ ├── in_anglvel_z_index
│ │ │ │ │ └── in_anglvel_z_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
│ │ │ │ ├── buffer
│ │ │ │ │ ├── enable
│ │ │ │ │ ├── length
│ │ │ │ │ └── watermark
│ │ │ │ ├── dev
│ │ │ │ ├── in_anglvel_hysteresis
│ │ │ │ ├── in_anglvel_offset
│ │ │ │ ├── in_anglvel_sampling_frequency
│ │ │ │ ├── in_anglvel_scale
│ │ │ │ ├── in_anglvel_x_raw
│ │ │ │ ├── in_anglvel_y_raw
│ │ │ │ ├── in_anglvel_z_raw
│ │ │ │ ├── name
│ │ │ │ ├── scan_elements
│ │ │ │ │ ├── in_anglvel_x_en
│ │ │ │ │ ├── in_anglvel_x_index
│ │ │ │ │ ├── in_anglvel_x_type
│ │ │ │ │ ├── in_anglvel_y_en
│ │ │ │ │ ├── in_anglvel_y_index
│ │ │ │ │ ├── in_anglvel_y_type
│ │ │ │ │ ├── in_anglvel_z_en
│ │ │ │ │ ├── in_anglvel_z_index
│ │ │ │ │ └── in_anglvel_z_type
│ │ │ │ ├── trigger
│ │ │ │ │ └── current_trigger
...
요약·해설
intel-ish-hid.rst:1-581Intel Integrated Sensor Hub는 sensor polling과 algorithm 처리를 저전력 co-processor에 맡기고, custom IPC와 ISHTP bus를 통해 firmware client를 Linux HID·IIO 계층에 연결합니다.
이 문서는 doorbell register, connection credit, DMA ownership, host enumeration, HID descriptor 등록, Lunar Lake firmware loader, vendor image 선택과 IIO sysfs 예제를 하나의 end-to-end 구조로 설명합니다.
Source와 구현 계층을 요약합니다.
Sensor firmware에서 userspace까지의 주 경로입니다.