요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
NNC와 uAPI
qaic.rst:62-159NNC wire envelope와 opaque command 책임을 나누고 nine driver-specific IOCTL의 BO state transition을 정의합니다.
Isolation과 tuning
qaic.rst:160-209Per-open resource ownership을 강제하고 polling·MHI·QSM·wait·timesync timeout parameter를 제공합니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0-only
=============
QAIC driver
=============
The QAIC driver is the Kernel Mode Driver (KMD) for the AIC100 family of AI
accelerator products.
Interrupts
==========
IRQ Storm Mitigation
--------------------
While the AIC100 DMA Bridge hardware implements an IRQ storm mitigation
mechanism, it is still possible for an IRQ storm to occur. A storm can happen
if the workload is particularly quick, and the host is responsive. If the host
can drain the response FIFO as quickly as the device can insert elements into
it, then the device will frequently transition the response FIFO from empty to
non-empty and generate MSIs at a rate equivalent to the speed of the
workload's ability to process inputs. The lprnet (license plate reader network)
workload is known to trigger this condition, and can generate in excess of 100k
MSIs per second. It has been observed that most systems cannot tolerate this
for long, and will crash due to some form of watchdog due to the overhead of
the interrupt controller interrupting the host CPU.
To mitigate this issue, the QAIC driver implements specific IRQ handling. When
QAIC receives an IRQ, it disables that line. This prevents the interrupt
controller from interrupting the CPU. Then AIC drains the FIFO. Once the FIFO
is drained, QAIC implements a "last chance" polling algorithm where QAIC will
sleep for a time to see if the workload will generate more activity. The IRQ
line remains disabled during this time. If no activity is detected, QAIC exits
polling mode and reenables the IRQ line.
This mitigation in QAIC is very effective. The same lprnet usecase that
generates 100k IRQs per second (per /proc/interrupts) is reduced to roughly 64
IRQs over 5 minutes while keeping the host system stable, and having the same
workload throughput performance (within run to run noise variation).
Single MSI Mode
---------------
MultiMSI is not well supported on all systems; virtualized ones even less so
(circa 2023). Between hypervisors masking the PCIe MSI capability structure to
large memory requirements for vIOMMUs (required for supporting MultiMSI), it is
useful to be able to fall back to a single MSI when needed.
To support this fallback, we allow the case where only one MSI is able to be
allocated, and share that one MSI between MHI and the DBCs. The device detects
when only one MSI has been configured and directs the interrupts for the DBCs
to the interrupt normally used for MHI. Unfortunately this means that the
interrupt handlers for every DBC and MHI wake up for every interrupt that
arrives; however, the DBC threaded irq handlers only are started when work to be
done is detected (MHI will always start its threaded handler).
If the DBC is configured to force MSI interrupts, this can circumvent the
software IRQ storm mitigation mentioned above. Since the MSI is shared it is
never disabled, allowing each new entry to the FIFO to trigger a new interrupt.
Neural Network Control (NNC) Protocol
=====================================
The implementation of NNC is split between the KMD (QAIC) and UMD. In general
QAIC understands how to encode/decode NNC wire protocol, and elements of the
protocol which require kernel space knowledge to process (for example, mapping
host memory to device IOVAs). QAIC understands the structure of a message, and
all of the transactions. QAIC does not understand commands (the payload of a
passthrough transaction).
QAIC handles and enforces the required little endianness and 64-bit alignment,
to the degree that it can. Since QAIC does not know the contents of a
passthrough transaction, it relies on the UMD to satisfy the requirements.
The terminate transaction is of particular use to QAIC. QAIC is not aware of
the resources that are loaded onto a device since the majority of that activity
occurs within NNC commands. As a result, QAIC does not have the means to
roll back userspace activity. To ensure that a userspace client's resources
are fully released in the case of a process crash, or a bug, QAIC uses the
terminate command to let QSM know when a user has gone away, and the resources
can be released.
QSM can report a version number of the NNC protocol it supports. This is in the
form of a Major number and a Minor number.
Major number updates indicate changes to the NNC protocol which impact the
message format, or transactions (impacts QAIC).
Minor number updates indicate changes to the NNC protocol which impact the
commands (does not impact QAIC).
uAPI
====
QAIC creates an accel device per physical PCIe device. This accel device exists
for as long as the PCIe device is known to Linux.
The PCIe device may not be in the state to accept requests from userspace at
all times. QAIC will trigger KOBJ_ONLINE/OFFLINE uevents to advertise when the
device can accept requests (ONLINE) and when the device is no longer accepting
requests (OFFLINE) because of a reset or other state transition.
QAIC defines a number of driver specific IOCTLs as part of the userspace API.
DRM_IOCTL_QAIC_MANAGE
This IOCTL allows userspace to send a NNC request to the QSM. The call will
block until a response is received, or the request has timed out.
DRM_IOCTL_QAIC_CREATE_BO
This IOCTL allows userspace to allocate a buffer object (BO) which can send
or receive data from a workload. The call will return a GEM handle that
represents the allocated buffer. The BO is not usable until it has been
sliced (see DRM_IOCTL_QAIC_ATTACH_SLICE_BO).
DRM_IOCTL_QAIC_MMAP_BO
This IOCTL allows userspace to prepare an allocated BO to be mmap'd into the
userspace process.
DRM_IOCTL_QAIC_ATTACH_SLICE_BO
This IOCTL allows userspace to slice a BO in preparation for sending the BO
to the device. Slicing is the operation of describing what portions of a BO
get sent where to a workload. This requires a set of DMA transfers for the
DMA Bridge, and as such, locks the BO to a specific DBC.
DRM_IOCTL_QAIC_EXECUTE_BO
This IOCTL allows userspace to submit a set of sliced BOs to the device. The
call is non-blocking. Success only indicates that the BOs have been queued
to the device, but does not guarantee they have been executed.
DRM_IOCTL_QAIC_PARTIAL_EXECUTE_BO
This IOCTL operates like DRM_IOCTL_QAIC_EXECUTE_BO, but it allows userspace
to shrink the BOs sent to the device for this specific call. If a BO
typically has N inputs, but only a subset of those is available, this IOCTL
allows userspace to indicate that only the first M bytes of the BO should be
sent to the device to minimize data transfer overhead. This IOCTL dynamically
recomputes the slicing, and therefore has some processing overhead before the
BOs can be queued to the device.
DRM_IOCTL_QAIC_WAIT_BO
This IOCTL allows userspace to determine when a particular BO has been
processed by the device. The call will block until either the BO has been
processed and can be re-queued to the device, or a timeout occurs.
DRM_IOCTL_QAIC_PERF_STATS_BO
This IOCTL allows userspace to collect performance statistics on the most
recent execution of a BO. This allows userspace to construct an end to end
timeline of the BO processing for a performance analysis.
DRM_IOCTL_QAIC_DETACH_SLICE_BO
This IOCTL allows userspace to remove the slicing information from a BO that
was originally provided by a call to DRM_IOCTL_QAIC_ATTACH_SLICE_BO. This
is the inverse of DRM_IOCTL_QAIC_ATTACH_SLICE_BO. The BO must be idle for
DRM_IOCTL_QAIC_DETACH_SLICE_BO to be called. After a successful detach slice
operation the BO may have new slicing information attached with a new call
to DRM_IOCTL_QAIC_ATTACH_SLICE_BO. After detach slice, the BO cannot be
executed until after a new attach slice operation. Combining attach slice
and detach slice calls allows userspace to use a BO with multiple workloads.
Userspace Client Isolation
==========================
AIC100 supports multiple clients. Multiple DBCs can be consumed by a single
client, and multiple clients can each consume one or more DBCs. Workloads
may contain sensitive information therefore only the client that owns the
workload should be allowed to interface with the DBC.
Clients are identified by the instance associated with their open(). A client
may only use memory they allocate, and DBCs that are assigned to their
workloads. Attempts to access resources assigned to other clients will be
rejected.
Module parameters
=================
QAIC supports the following module parameters:
**datapath_polling (bool)**
Configures QAIC to use a polling thread for datapath events instead of relying
on the device interrupts. Useful for platforms with broken multiMSI. Must be
set at QAIC driver initialization. Default is 0 (off).
**mhi_timeout_ms (unsigned int)**
Sets the timeout value for MHI operations in milliseconds (ms). Must be set
at the time the driver detects a device. Default is 2000 (2 seconds).
**control_resp_timeout_s (unsigned int)**
Sets the timeout value for QSM responses to NNC messages in seconds (s). Must
be set at the time the driver is sending a request to QSM. Default is 60 (one
minute).
**wait_exec_default_timeout_ms (unsigned int)**
Sets the default timeout for the wait_exec ioctl in milliseconds (ms). Must be
set prior to the waic_exec ioctl call. A value specified in the ioctl call
overrides this for that call. Default is 5000 (5 seconds).
**datapath_poll_interval_us (unsigned int)**
Sets the polling interval in microseconds (us) when datapath polling is active.
Takes effect at the next polling interval. Default is 100 (100 us).
**timesync_delay_ms (unsigned int)**
Sets the time interval in milliseconds (ms) between two consecutive timesync
operations. Default is 1000 (1000 ms).
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
QAIC Kernel Mode Driver
1-6`GPL-2.0-only` 문서입니다. QAIC driver는 AIC100 AI accelerator 제품군의 KMD(Kernel Mode Driver)입니다.
IRQ storm mitigation
7-39AIC100 DMA Bridge hardware에 IRQ storm mitigation이 있어도 workload가 매우 빠르고 host가 민첩하면 storm이 발생할 수 있습니다. Host가 device의 response FIFO insert 속도만큼 빨리 FIFO를 drain하면 FIFO가 empty에서 non-empty로 자주 전환되고 workload input 처리 속도와 같은 rate로 MSI가 발생합니다.
License plate reader network인 `lprnet` workload는 초당 MSI 100k개를 넘길 수 있습니다. 많은 system은 interrupt controller가 host CPU를 계속 interrupt하는 overhead를 오래 견디지 못하고 watchdog 형태의 문제로 crash하는 것이 관찰됐습니다.
QAIC는 IRQ를 받으면 해당 line을 disable해 interrupt controller가 CPU를 깨우지 못하게 한 뒤 FIFO를 drain합니다. FIFO가 비면 `last chance` polling으로 일정 시간 sleep하며 추가 activity를 확인하고, 그동안 IRQ line은 disable 상태를 유지합니다. Activity가 없으면 polling mode를 끝내고 IRQ line을 다시 enable합니다.
이 방식은 `/proc/interrupts`에서 초당 IRQ 100k개를 만들던 같은 `lprnet` use case를 5분 동안 약 64 IRQ로 줄였습니다. Host는 안정적이었고 workload throughput은 실행 간 noise 범위에서 동일했습니다.
IRQ line을 잠시 막고 FIFO를 비운 뒤 짧은 polling window로 burst를 흡수합니다.
Workload throughput을 유지하면서 host-visible IRQ rate를 낮춥니다.
Single MSI fallback
40-612023년 무렵 MultiMSI는 모든 system, 특히 virtualized system에서 충분히 지원되지 않았습니다. Hypervisor가 PCIe MSI capability structure를 mask하거나 MultiMSI에 필요한 vIOMMU memory 요구량이 커서 MSI 하나로 fallback하는 기능이 유용합니다.
QAIC는 MSI 하나만 allocate할 수 있는 경우 MHI와 모든 DBC가 이를 공유하도록 허용합니다. Device가 MSI 하나만 설정됐음을 감지하면 DBC interrupt를 보통 MHI가 쓰는 interrupt로 보냅니다. 모든 interrupt에서 모든 DBC와 MHI handler가 wake하지만, DBC threaded IRQ handler는 할 일이 감지될 때만 시작하고 MHI는 항상 threaded handler를 시작합니다.
DBC가 force MSI interrupt로 구성되면 앞의 software IRQ storm mitigation을 우회할 수 있습니다. Shared MSI는 disable되지 않으므로 FIFO의 새 entry마다 새 interrupt를 trigger할 수 있습니다.
MHI와 16 DBC interrupt source가 하나의 MSI로 합쳐집니다.
KMD와 UMD의 NNC protocol 분담
62-92NNC implementation은 KMD(QAIC)와 UMD로 나뉩니다. QAIC는 NNC wire protocol encode/decode, host memory를 device IOVA에 map하는 것처럼 kernel knowledge가 필요한 element를 처리합니다. Message structure와 모든 transaction을 이해하지만 passthrough transaction payload인 command 자체는 이해하지 않습니다.
QAIC는 가능한 범위에서 required little endianness와 64-bit alignment를 적용합니다. Passthrough 내용은 알 수 없으므로 그 payload의 requirement는 UMD가 충족해야 합니다.
`terminate` transaction은 QAIC에 특히 유용합니다. Resource load 대부분이 NNC command 안에서 일어나 QAIC는 device에 load된 resource를 알지 못하고 userspace activity를 rollback할 수 없습니다. Process crash나 bug로 client가 사라지면 QAIC가 `terminate`로 QSM에 알려 모든 resource를 release하게 합니다.
QSM은 지원하는 NNC protocol version을 Major와 Minor number로 보고합니다. Major update는 message format이나 transaction에 영향을 주므로 QAIC에 영향을 줍니다. Minor update는 command에 영향을 주며 QAIC에는 영향을 주지 않습니다.
KMD가 검증할 수 있는 wire envelope와 UMD가 책임지는 opaque command를 구분합니다.
Version component가 바뀌는 protocol surface입니다.
QAIC userspace API
93-159QAIC는 physical PCIe device마다 accel device 하나를 만들며 Linux가 PCIe device를 아는 동안 유지합니다. Device가 항상 userspace request를 받을 수 있는 것은 아닙니다. QAIC는 request 수락 가능 상태에 `KOBJ_ONLINE`, reset이나 다른 state transition으로 더 이상 수락하지 않을 때 `KOBJ_OFFLINE` uevent를 발생시킵니다.
Buffer lifecycle과 NNC control의 blocking·queue semantics를 보존합니다.
`DRM_IOCTL_QAIC_MANAGE`는 NNC request를 QSM에 보내고 response 수신 또는 timeout까지 block합니다. `DRM_IOCTL_QAIC_CREATE_BO`는 workload와 data를 주고받을 buffer object(BO)를 allocate하고 GEM handle을 반환합니다. BO는 `DRM_IOCTL_QAIC_ATTACH_SLICE_BO`로 slice하기 전에는 사용할 수 없습니다. `DRM_IOCTL_QAIC_MMAP_BO`는 allocated BO를 userspace process에 mmap할 준비를 합니다.
`DRM_IOCTL_QAIC_ATTACH_SLICE_BO`는 BO의 어느 부분을 workload의 어디로 보낼지 기술하는 slicing을 적용합니다. DMA Bridge용 DMA transfer set이 필요하므로 BO를 특정 DBC에 lock합니다. `DRM_IOCTL_QAIC_EXECUTE_BO`는 sliced BO set을 non-blocking으로 submit합니다. Success는 device queue에 들어갔다는 뜻일 뿐 실행 완료를 보장하지 않습니다.
`DRM_IOCTL_QAIC_PARTIAL_EXECUTE_BO`는 execute와 비슷하지만 이번 call에 보낼 BO를 줄일 수 있습니다. BO가 보통 input N개를 갖지만 일부만 준비됐다면 첫 M byte만 보내 transfer overhead를 줄입니다. Slicing을 동적으로 다시 계산하므로 queue 전에 processing overhead가 있습니다.
`DRM_IOCTL_QAIC_WAIT_BO`는 특정 BO가 처리돼 다시 queue할 수 있을 때까지 또는 timeout까지 block합니다. `DRM_IOCTL_QAIC_PERF_STATS_BO`는 가장 최근 BO 실행의 performance statistic을 수집해 end-to-end processing timeline을 구성하게 합니다.
`DRM_IOCTL_QAIC_DETACH_SLICE_BO`는 attach call로 넣은 slicing information을 제거하는 역연산이며 BO가 idle이어야 합니다. 성공 후 새 attach call로 다른 slicing을 붙일 수 있지만 다시 attach하기 전에는 실행할 수 없습니다. Attach와 detach를 조합하면 BO 하나를 여러 workload에서 사용할 수 있습니다.
Allocation부터 workload 재사용까지 필요한 state transition입니다.
Userspace client isolation
160-172AIC100은 multiple client를 지원합니다. Client 하나가 DBC 여러 개를 사용할 수 있고 여러 client가 각자 하나 이상의 DBC를 사용할 수도 있습니다. Workload에는 sensitive information이 있을 수 있으므로 해당 workload를 소유한 client만 DBC와 interface해야 합니다.
Client는 자신의 `open()`에 연관된 instance로 식별됩니다. 자신이 allocate한 memory와 자신의 workload에 배정된 DBC만 사용할 수 있으며 다른 client resource에 접근하려는 시도는 reject됩니다.
Memory와 DBC access를 open instance의 resource ownership으로 제한합니다.
Module parameters
173-209`datapath_polling`(bool)은 device interrupt 대신 polling thread로 datapath event를 처리합니다. MultiMSI가 고장 난 platform에 유용하고 QAIC driver initialization 때 설정해야 하며 default는 `0`(off)입니다.
`mhi_timeout_ms`(unsigned int)는 MHI operation timeout을 millisecond로 지정합니다. Driver가 device를 detect할 때 설정해야 하며 default는 `2000`(2 seconds)입니다. `control_resp_timeout_s`는 NNC message에 대한 QSM response timeout을 seconds로 지정하고 QSM request를 보낼 때 설정해야 하며 default는 `60`(1 minute)입니다.
`wait_exec_default_timeout_ms`는 `wait_exec` ioctl의 default timeout을 millisecond로 지정합니다. Source에 명시된 `waic_exec` ioctl call 전에 설정해야 하고 call에 지정한 값이 이번 call에서 override하며 default는 `5000`(5 seconds)입니다.
`datapath_poll_interval_us`는 datapath polling active 상태의 interval을 microseconds로 지정하며 다음 polling interval부터 적용됩니다. Default는 `100`(100 us)입니다. `timesync_delay_ms`는 연속된 timesync operation 사이의 interval을 milliseconds로 지정하며 default는 `1000`(1000 ms)입니다.
Type, application point와 default 값을 함께 정리합니다.
Interrupt handling
qaic.rst:1-61FIFO burst를 polling으로 흡수하고 MultiMSI가 어려운 platform에서는 MHI·DBC가 MSI 하나를 공유합니다.