Documentation/driver-api/surface_aggregator/internal.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

Surface Aggregator Core Driver Internals

SSAM core의 packet·request transport state machine, timeout·cancellation, controller event registration·delivery와 locking 계약을 다루는 한국어 전문 번역입니다.

Source pathDocumentation/driver-api/surface_aggregator/internal.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

internal.rst:1-578

이 문서는 SSAM core를 serdev 기반 Packet Transport Layer, command 기반 Request Transport Layer, client-facing Controller Layer로 나누고 각 계층에서 packet·request lifetime, queue와 pending set, retry·timeout, event notifier, concurrency와 locking이 어떻게 맞물리는지 설명합니다.

SSAM core 처리 지도
원문 줄핵심 내용
1-96API symbol 치환, core architecture와 계층 관계
97-287PTL packet state, queue·pending, transmitter·receiver, timeout·locking
288-462RTL request state, response matching, timeout·locking
463-513Controller 책임과 event class registration
514-578Event queue delivery, ordering, controller concurrency

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0+
2
3 .. |ssh_ptl| replace:: :c:type:`struct ssh_ptl <ssh_ptl>`
4 .. |ssh_ptl_submit| replace:: :c:func:`ssh_ptl_submit`
5 .. |ssh_ptl_cancel| replace:: :c:func:`ssh_ptl_cancel`
6 .. |ssh_ptl_shutdown| replace:: :c:func:`ssh_ptl_shutdown`
7 .. |ssh_ptl_rx_rcvbuf| replace:: :c:func:`ssh_ptl_rx_rcvbuf`
8 .. |ssh_rtl| replace:: :c:type:`struct ssh_rtl <ssh_rtl>`
9 .. |ssh_rtl_submit| replace:: :c:func:`ssh_rtl_submit`
10 .. |ssh_rtl_cancel| replace:: :c:func:`ssh_rtl_cancel`
11 .. |ssh_rtl_shutdown| replace:: :c:func:`ssh_rtl_shutdown`
12 .. |ssh_packet| replace:: :c:type:`struct ssh_packet <ssh_packet>`
13 .. |ssh_packet_get| replace:: :c:func:`ssh_packet_get`
14 .. |ssh_packet_put| replace:: :c:func:`ssh_packet_put`
15 .. |ssh_packet_ops| replace:: :c:type:`struct ssh_packet_ops <ssh_packet_ops>`
16 .. |ssh_packet_base_priority| replace:: :c:type:`enum ssh_packet_base_priority <ssh_packet_base_priority>`
17 .. |ssh_packet_flags| replace:: :c:type:`enum ssh_packet_flags <ssh_packet_flags>`
18 .. |SSH_PACKET_PRIORITY| replace:: :c:func:`SSH_PACKET_PRIORITY`
19 .. |ssh_frame| replace:: :c:type:`struct ssh_frame <ssh_frame>`
20 .. |ssh_command| replace:: :c:type:`struct ssh_command <ssh_command>`
21 .. |ssh_request| replace:: :c:type:`struct ssh_request <ssh_request>`
22 .. |ssh_request_get| replace:: :c:func:`ssh_request_get`
23 .. |ssh_request_put| replace:: :c:func:`ssh_request_put`
24 .. |ssh_request_ops| replace:: :c:type:`struct ssh_request_ops <ssh_request_ops>`
25 .. |ssh_request_init| replace:: :c:func:`ssh_request_init`
26 .. |ssh_request_flags| replace:: :c:type:`enum ssh_request_flags <ssh_request_flags>`
27 .. |ssam_controller| replace:: :c:type:`struct ssam_controller <ssam_controller>`
28 .. |ssam_device| replace:: :c:type:`struct ssam_device <ssam_device>`
29 .. |ssam_device_driver| replace:: :c:type:`struct ssam_device_driver <ssam_device_driver>`
30 .. |ssam_client_bind| replace:: :c:func:`ssam_client_bind`
31 .. |ssam_client_link| replace:: :c:func:`ssam_client_link`
32 .. |ssam_request_sync| replace:: :c:type:`struct ssam_request_sync <ssam_request_sync>`
33 .. |ssam_event_registry| replace:: :c:type:`struct ssam_event_registry <ssam_event_registry>`
34 .. |ssam_event_id| replace:: :c:type:`struct ssam_event_id <ssam_event_id>`
35 .. |ssam_nf| replace:: :c:type:`struct ssam_nf <ssam_nf>`
36 .. |ssam_nf_refcount_inc| replace:: :c:func:`ssam_nf_refcount_inc`
37 .. |ssam_nf_refcount_dec| replace:: :c:func:`ssam_nf_refcount_dec`
38 .. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
39 .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
40 .. |ssam_cplt| replace:: :c:type:`struct ssam_cplt <ssam_cplt>`
41 .. |ssam_event_queue| replace:: :c:type:`struct ssam_event_queue <ssam_event_queue>`
42 .. |ssam_request_sync_submit| replace:: :c:func:`ssam_request_sync_submit`
43
44 =====================
45 Core Driver Internals
46 =====================
47
48 Architectural overview of the Surface System Aggregator Module (SSAM) core
49 and Surface Serial Hub (SSH) driver. For the API documentation, refer to:
50
51 .. toctree::
52 :maxdepth: 2
53
54 internal-api
55
56
57 Overview
58 ========
59
60 The SSAM core implementation is structured in layers, somewhat following the
61 SSH protocol structure:
62
63 Lower-level packet transport is implemented in the *packet transport layer
64 (PTL)*, directly building on top of the serial device (serdev)
65 infrastructure of the kernel. As the name indicates, this layer deals with
66 the packet transport logic and handles things like packet validation, packet
67 acknowledgment (ACKing), packet (retransmission) timeouts, and relaying
68 packet payloads to higher-level layers.
69
70 Above this sits the *request transport layer (RTL)*. This layer is centered
71 around command-type packet payloads, i.e. requests (sent from host to EC),
72 responses of the EC to those requests, and events (sent from EC to host).
73 It, specifically, distinguishes events from request responses, matches
74 responses to their corresponding requests, and implements request timeouts.
75
76 The *controller* layer is building on top of this and essentially decides
77 how request responses and, especially, events are dealt with. It provides an
78 event notifier system, handles event activation/deactivation, provides a
79 workqueue for event and asynchronous request completion, and also manages
80 the message counters required for building command messages (``SEQ``,
81 ``RQID``). This layer basically provides a fundamental interface to the SAM
82 EC for use in other kernel drivers.
83
84 While the controller layer already provides an interface for other kernel
85 drivers, the client *bus* extends this interface to provide support for
86 native SSAM devices, i.e. devices that are not defined in ACPI and not
87 implemented as platform devices, via |ssam_device| and |ssam_device_driver|
88 simplify management of client devices and client drivers.
89
90 Refer to Documentation/driver-api/surface_aggregator/client.rst for
91 documentation regarding the client device/driver API and interface options
92 for other kernel drivers. It is recommended to familiarize oneself with
93 that chapter and the Documentation/driver-api/surface_aggregator/ssh.rst
94 before continuing with the architectural overview below.
95
96
97 Packet Transport Layer
98 ======================
99
100 The packet transport layer is represented via |ssh_ptl| and is structured
101 around the following key concepts:
102
103 Packets
104 -------
105
106 Packets are the fundamental transmission unit of the SSH protocol. They are
107 managed by the packet transport layer, which is essentially the lowest layer
108 of the driver and is built upon by other components of the SSAM core.
109 Packets to be transmitted by the SSAM core are represented via |ssh_packet|
110 (in contrast, packets received by the core do not have any specific
111 structure and are managed entirely via the raw |ssh_frame|).
112
113 This structure contains the required fields to manage the packet inside the
114 transport layer, as well as a reference to the buffer containing the data to
115 be transmitted (i.e. the message wrapped in |ssh_frame|). Most notably, it
116 contains an internal reference count, which is used for managing its
117 lifetime (accessible via |ssh_packet_get| and |ssh_packet_put|). When this
118 counter reaches zero, the ``release()`` callback provided to the packet via
119 its |ssh_packet_ops| reference is executed, which may then deallocate the
120 packet or its enclosing structure (e.g. |ssh_request|).
121
122 In addition to the ``release`` callback, the |ssh_packet_ops| reference also
123 provides a ``complete()`` callback, which is run once the packet has been
124 completed and provides the status of this completion, i.e. zero on success
125 or a negative errno value in case of an error. Once the packet has been
126 submitted to the packet transport layer, the ``complete()`` callback is
127 always guaranteed to be executed before the ``release()`` callback, i.e. the
128 packet will always be completed, either successfully, with an error, or due
129 to cancellation, before it will be released.
130
131 The state of a packet is managed via its ``state`` flags
132 (|ssh_packet_flags|), which also contains the packet type. In particular,
133 the following bits are noteworthy:
134
135 * ``SSH_PACKET_SF_LOCKED_BIT``: This bit is set when completion, either
136 through error or success, is imminent. It indicates that no further
137 references of the packet should be taken and any existing references
138 should be dropped as soon as possible. The process setting this bit is
139 responsible for removing any references to this packet from the packet
140 queue and pending set.
141
142 * ``SSH_PACKET_SF_COMPLETED_BIT``: This bit is set by the process running the
143 ``complete()`` callback and is used to ensure that this callback only runs
144 once.
145
146 * ``SSH_PACKET_SF_QUEUED_BIT``: This bit is set when the packet is queued on
147 the packet queue and cleared when it is dequeued.
148
149 * ``SSH_PACKET_SF_PENDING_BIT``: This bit is set when the packet is added to
150 the pending set and cleared when it is removed from it.
151
152 Packet Queue
153 ------------
154
155 The packet queue is the first of the two fundamental collections in the
156 packet transport layer. It is a priority queue, with priority of the
157 respective packets based on the packet type (major) and number of tries
158 (minor). See |SSH_PACKET_PRIORITY| for more details on the priority value.
159
160 All packets to be transmitted by the transport layer must be submitted to
161 this queue via |ssh_ptl_submit|. Note that this includes control packets
162 sent by the transport layer itself. Internally, data packets can be
163 re-submitted to this queue due to timeouts or NAK packets sent by the EC.
164
165 Pending Set
166 -----------
167
168 The pending set is the second of the two fundamental collections in the
169 packet transport layer. It stores references to packets that have already
170 been transmitted, but wait for acknowledgment (e.g. the corresponding ACK
171 packet) by the EC.
172
173 Note that a packet may both be pending and queued if it has been
174 re-submitted due to a packet acknowledgment timeout or NAK. On such a
175 re-submission, packets are not removed from the pending set.
176
177 Transmitter Thread
178 ------------------
179
180 The transmitter thread is responsible for most of the actual work regarding
181 packet transmission. In each iteration, it (waits for and) checks if the
182 next packet on the queue (if any) can be transmitted and, if so, removes it
183 from the queue and increments its counter for the number of transmission
184 attempts, i.e. tries. If the packet is sequenced, i.e. requires an ACK by
185 the EC, the packet is added to the pending set. Next, the packet's data is
186 submitted to the serdev subsystem. In case of an error or timeout during
187 this submission, the packet is completed by the transmitter thread with the
188 status value of the callback set accordingly. In case the packet is
189 unsequenced, i.e. does not require an ACK by the EC, the packet is completed
190 with success on the transmitter thread.
191
192 Transmission of sequenced packets is limited by the number of concurrently
193 pending packets, i.e. a limit on how many packets may be waiting for an ACK
194 from the EC in parallel. This limit is currently set to one (see
195 Documentation/driver-api/surface_aggregator/ssh.rst for the reasoning behind
196 this). Control packets (i.e. ACK and NAK) can always be transmitted.
197
198 Receiver Thread
199 ---------------
200
201 Any data received from the EC is put into a FIFO buffer for further
202 processing. This processing happens on the receiver thread. The receiver
203 thread parses and validates the received message into its |ssh_frame| and
204 corresponding payload. It prepares and submits the necessary ACK (and on
205 validation error or invalid data NAK) packets for the received messages.
206
207 This thread also handles further processing, such as matching ACK messages
208 to the corresponding pending packet (via sequence ID) and completing it, as
209 well as initiating re-submission of all currently pending packets on
210 receival of a NAK message (re-submission in case of a NAK is similar to
211 re-submission due to timeout, see below for more details on that). Note that
212 the successful completion of a sequenced packet will always run on the
213 receiver thread (whereas any failure-indicating completion will run on the
214 process where the failure occurred).
215
216 Any payload data is forwarded via a callback to the next upper layer, i.e.
217 the request transport layer.
218
219 Timeout Reaper
220 --------------
221
222 The packet acknowledgment timeout is a per-packet timeout for sequenced
223 packets, started when the respective packet begins (re-)transmission (i.e.
224 this timeout is armed once per transmission attempt on the transmitter
225 thread). It is used to trigger re-submission or, when the number of tries
226 has been exceeded, cancellation of the packet in question.
227
228 This timeout is handled via a dedicated reaper task, which is essentially a
229 work item (re-)scheduled to run when the next packet is set to time out. The
230 work item then checks the set of pending packets for any packets that have
231 exceeded the timeout and, if there are any remaining packets, re-schedules
232 itself to the next appropriate point in time.
233
234 If a timeout has been detected by the reaper, the packet will either be
235 re-submitted if it still has some remaining tries left, or completed with
236 ``-ETIMEDOUT`` as status if not. Note that re-submission, in this case and
237 triggered by receival of a NAK, means that the packet is added to the queue
238 with a now incremented number of tries, yielding a higher priority. The
239 timeout for the packet will be disabled until the next transmission attempt
240 and the packet remains on the pending set.
241
242 Note that due to transmission and packet acknowledgment timeouts, the packet
243 transport layer is always guaranteed to make progress, if only through
244 timing out packets, and will never fully block.
245
246 Concurrency and Locking
247 -----------------------
248
249 There are two main locks in the packet transport layer: One guarding access
250 to the packet queue and one guarding access to the pending set. These
251 collections may only be accessed and modified under the respective lock. If
252 access to both collections is needed, the pending lock must be acquired
253 before the queue lock to avoid deadlocks.
254
255 In addition to guarding the collections, after initial packet submission
256 certain packet fields may only be accessed under one of the locks.
257 Specifically, the packet priority must only be accessed while holding the
258 queue lock and the packet timestamp must only be accessed while holding the
259 pending lock.
260
261 Other parts of the packet transport layer are guarded independently. State
262 flags are managed by atomic bit operations and, if necessary, memory
263 barriers. Modifications to the timeout reaper work item and expiration date
264 are guarded by their own lock.
265
266 The reference of the packet to the packet transport layer (``ptl``) is
267 somewhat special. It is either set when the upper layer request is submitted
268 or, if there is none, when the packet is first submitted. After it is set,
269 it will not change its value. Functions that may run concurrently with
270 submission, i.e. cancellation, can not rely on the ``ptl`` reference to be
271 set. Access to it in these functions is guarded by ``READ_ONCE()``, whereas
272 setting ``ptl`` is equally guarded with ``WRITE_ONCE()`` for symmetry.
273
274 Some packet fields may be read outside of the respective locks guarding
275 them, specifically priority and state for tracing. In those cases, proper
276 access is ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``. Such
277 read-only access is only allowed when stale values are not critical.
278
279 With respect to the interface for higher layers, packet submission
280 (|ssh_ptl_submit|), packet cancellation (|ssh_ptl_cancel|), data receival
281 (|ssh_ptl_rx_rcvbuf|), and layer shutdown (|ssh_ptl_shutdown|) may always be
282 executed concurrently with respect to each other. Note that packet
283 submission may not run concurrently with itself for the same packet.
284 Equally, shutdown and data receival may also not run concurrently with
285 themselves (but may run concurrently with each other).
286
287
288 Request Transport Layer
289 =======================
290
291 The request transport layer is represented via |ssh_rtl| and builds on top
292 of the packet transport layer. It deals with requests, i.e. SSH packets sent
293 by the host containing a |ssh_command| as frame payload. This layer
294 separates responses to requests from events, which are also sent by the EC
295 via a |ssh_command| payload. While responses are handled in this layer,
296 events are relayed to the next upper layer, i.e. the controller layer, via
297 the corresponding callback. The request transport layer is structured around
298 the following key concepts:
299
300 Request
301 -------
302
303 Requests are packets with a command-type payload, sent from host to EC to
304 query data from or trigger an action on it (or both simultaneously). They
305 are represented by |ssh_request|, wrapping the underlying |ssh_packet|
306 storing its message data (i.e. SSH frame with command payload). Note that
307 all top-level representations, e.g. |ssam_request_sync| are built upon this
308 struct.
309
310 As |ssh_request| extends |ssh_packet|, its lifetime is also managed by the
311 reference counter inside the packet struct (which can be accessed via
312 |ssh_request_get| and |ssh_request_put|). Once the counter reaches zero, the
313 ``release()`` callback of the |ssh_request_ops| reference of the request is
314 called.
315
316 Requests can have an optional response that is equally sent via a SSH
317 message with command-type payload (from EC to host). The party constructing
318 the request must know if a response is expected and mark this in the request
319 flags provided to |ssh_request_init|, so that the request transport layer
320 can wait for this response.
321
322 Similar to |ssh_packet|, |ssh_request| also has a ``complete()`` callback
323 provided via its request ops reference and is guaranteed to be completed
324 before it is released once it has been submitted to the request transport
325 layer via |ssh_rtl_submit|. For a request without a response, successful
326 completion will occur once the underlying packet has been successfully
327 transmitted by the packet transport layer (i.e. from within the packet
328 completion callback). For a request with response, successful completion
329 will occur once the response has been received and matched to the request
330 via its request ID (which happens on the packet layer's data-received
331 callback running on the receiver thread). If the request is completed with
332 an error, the status value will be set to the corresponding (negative) errno
333 value.
334
335 The state of a request is again managed via its ``state`` flags
336 (|ssh_request_flags|), which also encode the request type. In particular,
337 the following bits are noteworthy:
338
339 * ``SSH_REQUEST_SF_LOCKED_BIT``: This bit is set when completion, either
340 through error or success, is imminent. It indicates that no further
341 references of the request should be taken and any existing references
342 should be dropped as soon as possible. The process setting this bit is
343 responsible for removing any references to this request from the request
344 queue and pending set.
345
346 * ``SSH_REQUEST_SF_COMPLETED_BIT``: This bit is set by the process running the
347 ``complete()`` callback and is used to ensure that this callback only runs
348 once.
349
350 * ``SSH_REQUEST_SF_QUEUED_BIT``: This bit is set when the request is queued on
351 the request queue and cleared when it is dequeued.
352
353 * ``SSH_REQUEST_SF_PENDING_BIT``: This bit is set when the request is added to
354 the pending set and cleared when it is removed from it.
355
356 Request Queue
357 -------------
358
359 The request queue is the first of the two fundamental collections in the
360 request transport layer. In contrast to the packet queue of the packet
361 transport layer, it is not a priority queue and the simple first come first
362 serve principle applies.
363
364 All requests to be transmitted by the request transport layer must be
365 submitted to this queue via |ssh_rtl_submit|. Once submitted, requests may
366 not be re-submitted, and will not be re-submitted automatically on timeout.
367 Instead, the request is completed with a timeout error. If desired, the
368 caller can create and submit a new request for another try, but it must not
369 submit the same request again.
370
371 Pending Set
372 -----------
373
374 The pending set is the second of the two fundamental collections in the
375 request transport layer. This collection stores references to all pending
376 requests, i.e. requests awaiting a response from the EC (similar to what the
377 pending set of the packet transport layer does for packets).
378
379 Transmitter Task
380 ----------------
381
382 The transmitter task is scheduled when a new request is available for
383 transmission. It checks if the next request on the request queue can be
384 transmitted and, if so, submits its underlying packet to the packet
385 transport layer. This check ensures that only a limited number of
386 requests can be pending, i.e. waiting for a response, at the same time. If
387 the request requires a response, the request is added to the pending set
388 before its packet is submitted.
389
390 Packet Completion Callback
391 --------------------------
392
393 The packet completion callback is executed once the underlying packet of a
394 request has been completed. In case of an error completion, the
395 corresponding request is completed with the error value provided in this
396 callback.
397
398 On successful packet completion, further processing depends on the request.
399 If the request expects a response, it is marked as transmitted and the
400 request timeout is started. If the request does not expect a response, it is
401 completed with success.
402
403 Data-Received Callback
404 ----------------------
405
406 The data received callback notifies the request transport layer of data
407 being received by the underlying packet transport layer via a data-type
408 frame. In general, this is expected to be a command-type payload.
409
410 If the request ID of the command is one of the request IDs reserved for
411 events (one to ``SSH_NUM_EVENTS``, inclusively), it is forwarded to the
412 event callback registered in the request transport layer. If the request ID
413 indicates a response to a request, the respective request is looked up in
414 the pending set and, if found and marked as transmitted, completed with
415 success.
416
417 Timeout Reaper
418 --------------
419
420 The request-response-timeout is a per-request timeout for requests expecting
421 a response. It is used to ensure that a request does not wait indefinitely
422 on a response from the EC and is started after the underlying packet has
423 been successfully completed.
424
425 This timeout is, similar to the packet acknowledgment timeout on the packet
426 transport layer, handled via a dedicated reaper task. This task is
427 essentially a work-item (re-)scheduled to run when the next request is set
428 to time out. The work item then scans the set of pending requests for any
429 requests that have timed out and completes them with ``-ETIMEDOUT`` as
430 status. Requests will not be re-submitted automatically. Instead, the issuer
431 of the request must construct and submit a new request, if so desired.
432
433 Note that this timeout, in combination with packet transmission and
434 acknowledgment timeouts, guarantees that the request layer will always make
435 progress, even if only through timing out packets, and never fully block.
436
437 Concurrency and Locking
438 -----------------------
439
440 Similar to the packet transport layer, there are two main locks in the
441 request transport layer: One guarding access to the request queue and one
442 guarding access to the pending set. These collections may only be accessed
443 and modified under the respective lock.
444
445 Other parts of the request transport layer are guarded independently. State
446 flags are (again) managed by atomic bit operations and, if necessary, memory
447 barriers. Modifications to the timeout reaper work item and expiration date
448 are guarded by their own lock.
449
450 Some request fields may be read outside of the respective locks guarding
451 them, specifically the state for tracing. In those cases, proper access is
452 ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``. Such read-only
453 access is only allowed when stale values are not critical.
454
455 With respect to the interface for higher layers, request submission
456 (|ssh_rtl_submit|), request cancellation (|ssh_rtl_cancel|), and layer
457 shutdown (|ssh_rtl_shutdown|) may always be executed concurrently with
458 respect to each other. Note that request submission may not run concurrently
459 with itself for the same request (and also may only be called once per
460 request). Equally, shutdown may also not run concurrently with itself.
461
462
463 Controller Layer
464 ================
465
466 The controller layer extends on the request transport layer to provide an
467 easy-to-use interface for client drivers. It is represented by
468 |ssam_controller| and the SSH driver. While the lower level transport layers
469 take care of transmitting and handling packets and requests, the controller
470 layer takes on more of a management role. Specifically, it handles device
471 initialization, power management, and event handling, including event
472 delivery and registration via the (event) completion system (|ssam_cplt|).
473
474 Event Registration
475 ------------------
476
477 In general, an event (or rather a class of events) has to be explicitly
478 requested by the host before the EC will send it (HID input events seem to
479 be the exception). This is done via an event-enable request (similarly,
480 events should be disabled via an event-disable request once no longer
481 desired).
482
483 The specific request used to enable (or disable) an event is given via an
484 event registry, i.e. the governing authority of this event (so to speak),
485 represented by |ssam_event_registry|. As parameters to this request, the
486 target category and, depending on the event registry, instance ID of the
487 event to be enabled must be provided. This (optional) instance ID must be
488 zero if the registry does not use it. Together, target category and instance
489 ID form the event ID, represented by |ssam_event_id|. In short, both, event
490 registry and event ID, are required to uniquely identify a respective class
491 of events.
492
493 Note that a further *request ID* parameter must be provided for the
494 enable-event request. This parameter does not influence the class of events
495 being enabled, but instead is set as the request ID (RQID) on each event of
496 this class sent by the EC. It is used to identify events (as a limited
497 number of request IDs is reserved for use in events only, specifically one
498 to ``SSH_NUM_EVENTS`` inclusively) and also map events to their specific
499 class. Currently, the controller always sets this parameter to the target
500 category specified in |ssam_event_id|.
501
502 As multiple client drivers may rely on the same (or overlapping) classes of
503 events and enable/disable calls are strictly binary (i.e. on/off), the
504 controller has to manage access to these events. It does so via reference
505 counting, storing the counter inside an RB-tree based mapping with event
506 registry and ID as key (there is no known list of valid event registry and
507 event ID combinations). See |ssam_nf|, |ssam_nf_refcount_inc|, and
508 |ssam_nf_refcount_dec| for details.
509
510 This management is done together with notifier registration (described in
511 the next section) via the top-level |ssam_notifier_register| and
512 |ssam_notifier_unregister| functions.
513
514 Event Delivery
515 --------------
516
517 To receive events, a client driver has to register an event notifier via
518 |ssam_notifier_register|. This increments the reference counter for that
519 specific class of events (as detailed in the previous section), enables the
520 class on the EC (if it has not been enabled already), and installs the
521 provided notifier callback.
522
523 Notifier callbacks are stored in lists, with one (RCU) list per target
524 category (provided via the event ID; NB: there is a fixed known number of
525 target categories). There is no known association from the combination of
526 event registry and event ID to the command data (target ID, target category,
527 command ID, and instance ID) that can be provided by an event class, apart
528 from target category and instance ID given via the event ID.
529
530 Note that due to the way notifiers are (or rather have to be) stored, client
531 drivers may receive events that they have not requested and need to account
532 for them. Specifically, they will, by default, receive all events from the
533 same target category. To simplify dealing with this, filtering of events by
534 target ID (provided via the event registry) and instance ID (provided via
535 the event ID) can be requested when registering a notifier. This filtering
536 is applied when iterating over the notifiers at the time they are executed.
537
538 All notifier callbacks are executed on a dedicated workqueue, the so-called
539 completion workqueue. After an event has been received via the callback
540 installed in the request layer (running on the receiver thread of the packet
541 transport layer), it will be put on its respective event queue
542 (|ssam_event_queue|). From this event queue the completion work item of that
543 queue (running on the completion workqueue) will pick up the event and
544 execute the notifier callback. This is done to avoid blocking on the
545 receiver thread.
546
547 There is one event queue per combination of target ID and target category.
548 This is done to ensure that notifier callbacks are executed in sequence for
549 events of the same target ID and target category. Callbacks can be executed
550 in parallel for events with a different combination of target ID and target
551 category.
552
553 Concurrency and Locking
554 -----------------------
555
556 Most of the concurrency related safety guarantees of the controller are
557 provided by the lower-level request transport layer. In addition to this,
558 event (un-)registration is guarded by its own lock.
559
560 Access to the controller state is guarded by the state lock. This lock is a
561 read/write semaphore. The reader part can be used to ensure that the state
562 does not change while functions depending on the state to stay the same
563 (e.g. |ssam_notifier_register|, |ssam_notifier_unregister|,
564 |ssam_request_sync_submit|, and derivatives) are executed and this guarantee
565 is not already provided otherwise (e.g. through |ssam_client_bind| or
566 |ssam_client_link|). The writer part guards any transitions that will change
567 the state, i.e. initialization, destruction, suspension, and resumption.
568
569 The controller state may be accessed (read-only) outside the state lock for
570 smoke-testing against invalid API usage (e.g. in |ssam_request_sync_submit|).
571 Note that such checks are not supposed to (and will not) protect against all
572 invalid usages, but rather aim to help catch them. In those cases, proper
573 variable access is ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``.
574
575 Assuming any preconditions on the state not changing have been satisfied,
576 all non-initialization and non-shutdown functions may run concurrently with
577 each other. This includes |ssam_notifier_register|, |ssam_notifier_unregister|,
578 |ssam_request_sync_submit|, as well as all functions building on top of those.
579

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

문서 치환 symbol

1-44

이 문서는 `GPL-2.0+` SPDX license를 사용합니다. 머리말의 replace 지시문은 packet transport layer(PTL), request transport layer(RTL), packet·request·controller·event 관련 C type과 function을 본문에서 일관된 kernel-doc 교차 참조로 표시합니다.

PTL 관련 치환에는 `ssh_ptl`, `ssh_ptl_submit`, `ssh_ptl_cancel`, `ssh_ptl_shutdown`, `ssh_ptl_rx_rcvbuf`가 있고, RTL 관련 치환에는 `ssh_rtl`, `ssh_rtl_submit`, `ssh_rtl_cancel`, `ssh_rtl_shutdown`이 있습니다.

Packet과 request lifecycle은 `ssh_packet`, `ssh_packet_get`, `ssh_packet_put`, `ssh_packet_ops`, `ssh_packet_flags`, `ssh_request`, `ssh_request_get`, `ssh_request_put`, `ssh_request_ops`, `ssh_request_init`, `ssh_request_flags` 등의 symbol로 설명합니다.

상위 계층은 `ssam_controller`, `ssam_device`, `ssam_device_driver`, `ssam_event_registry`, `ssam_event_id`, `ssam_nf`, notifier 등록·해제, completion system, event queue, synchronous request API를 참조합니다.

치환 symbol 그룹
계층대표 symbol
Packet transport`ssh_ptl`, `ssh_packet`, `ssh_frame`, `SSH_PACKET_PRIORITY`
Request transport`ssh_rtl`, `ssh_command`, `ssh_request`, `ssh_request_init`
Controller and clients`ssam_controller`, `ssam_device`, `ssam_client_bind`, `ssam_client_link`
Events and completion`ssam_event_registry`, `ssam_event_id`, `ssam_nf`, `ssam_cplt`, `ssam_event_queue`

.. SPDX-License-Identifier: GPL-2.0+

.. |ssh_ptl| replace:: :c:type:`struct ssh_ptl <ssh_ptl>`
.. |ssh_ptl_submit| replace:: :c:func:`ssh_ptl_submit`
.. |ssh_ptl_cancel| replace:: :c:func:`ssh_ptl_cancel`
.. |ssh_ptl_shutdown| replace:: :c:func:`ssh_ptl_shutdown`
.. |ssh_ptl_rx_rcvbuf| replace:: :c:func:`ssh_ptl_rx_rcvbuf`
.. |ssh_rtl| replace:: :c:type:`struct ssh_rtl <ssh_rtl>`
.. |ssh_rtl_submit| replace:: :c:func:`ssh_rtl_submit`
.. |ssh_rtl_cancel| replace:: :c:func:`ssh_rtl_cancel`
.. |ssh_rtl_shutdown| replace:: :c:func:`ssh_rtl_shutdown`
.. |ssh_packet| replace:: :c:type:`struct ssh_packet <ssh_packet>`
.. |ssh_packet_get| replace:: :c:func:`ssh_packet_get`
.. |ssh_packet_put| replace:: :c:func:`ssh_packet_put`
.. |ssh_packet_ops| replace:: :c:type:`struct ssh_packet_ops <ssh_packet_ops>`
.. |ssh_packet_base_priority| replace:: :c:type:`enum ssh_packet_base_priority <ssh_packet_base_priority>`
.. |ssh_packet_flags| replace:: :c:type:`enum ssh_packet_flags <ssh_packet_flags>`
.. |SSH_PACKET_PRIORITY| replace:: :c:func:`SSH_PACKET_PRIORITY`
.. |ssh_frame| replace:: :c:type:`struct ssh_frame <ssh_frame>`
.. |ssh_command| replace:: :c:type:`struct ssh_command <ssh_command>`
.. |ssh_request| replace:: :c:type:`struct ssh_request <ssh_request>`
.. |ssh_request_get| replace:: :c:func:`ssh_request_get`
.. |ssh_request_put| replace:: :c:func:`ssh_request_put`
.. |ssh_request_ops| replace:: :c:type:`struct ssh_request_ops <ssh_request_ops>`
.. |ssh_request_init| replace:: :c:func:`ssh_request_init`
.. |ssh_request_flags| replace:: :c:type:`enum ssh_request_flags <ssh_request_flags>`
.. |ssam_controller| replace:: :c:type:`struct ssam_controller <ssam_controller>`
.. |ssam_device| replace:: :c:type:`struct ssam_device <ssam_device>`
.. |ssam_device_driver| replace:: :c:type:`struct ssam_device_driver <ssam_device_driver>`
.. |ssam_client_bind| replace:: :c:func:`ssam_client_bind`
.. |ssam_client_link| replace:: :c:func:`ssam_client_link`
.. |ssam_request_sync| replace:: :c:type:`struct ssam_request_sync <ssam_request_sync>`
.. |ssam_event_registry| replace:: :c:type:`struct ssam_event_registry <ssam_event_registry>`
.. |ssam_event_id| replace:: :c:type:`struct ssam_event_id <ssam_event_id>`
.. |ssam_nf| replace:: :c:type:`struct ssam_nf <ssam_nf>`
.. |ssam_nf_refcount_inc| replace:: :c:func:`ssam_nf_refcount_inc`
.. |ssam_nf_refcount_dec| replace:: :c:func:`ssam_nf_refcount_dec`
.. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
.. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
.. |ssam_cplt| replace:: :c:type:`struct ssam_cplt <ssam_cplt>`
.. |ssam_event_queue| replace:: :c:type:`struct ssam_event_queue <ssam_event_queue>`
.. |ssam_request_sync_submit| replace:: :c:func:`ssam_request_sync_submit`

=====================

Core Driver Internals

45-56

이 장은 Surface System Aggregator Module(SSAM) core와 Surface Serial Hub(SSH) driver의 architecture를 설명합니다.

구체적인 internal API 문서는 최대 깊이 2의 `toctree`로 연결된 `internal-api` 문서를 참조합니다.

문서 범위
항목내용
CoreSurface System Aggregator Module (SSAM)
TransportSurface Serial Hub (SSH)
API reference`internal-api`

Core Driver Internals
=====================

Architectural overview of the Surface System Aggregator Module (SSAM) core
and Surface Serial Hub (SSH) driver. For the API documentation, refer to:

.. toctree::
   :maxdepth: 2

   internal-api

계층 구조 개요

57-96

SSAM core 구현은 SSH protocol 구조를 대체로 따라 여러 계층으로 구성됩니다.

가장 아래의 packet transport layer(PTL)는 kernel의 serial device(serdev) infrastructure 위에 직접 구축됩니다. Packet validation, ACK 처리, packet 재전송 timeout, payload를 상위 계층으로 전달하는 일을 담당합니다.

그 위의 request transport layer(RTL)는 command형 packet payload를 다룹니다. Host에서 EC로 보내는 request, 그 request에 대한 EC response, EC에서 host로 보내는 event를 구분하고, response를 대응 request와 match하며, request timeout을 구현합니다.

Controller layer는 response와 특히 event를 처리하는 정책을 제공합니다. Event notifier, event 활성화·비활성화, event 및 asynchronous request completion용 workqueue, command message의 `SEQ`·`RQID` counter를 관리하여 다른 kernel driver가 SAM EC를 사용할 수 있는 기본 interface를 제공합니다.

Client bus는 ACPI에 정의되지 않고 platform device로 구현되지 않은 native SSAM device를 `ssam_device`와 `ssam_device_driver`로 지원하여 client device와 driver 관리를 단순화합니다.

계속 읽기 전에 `Documentation/driver-api/surface_aggregator/client.rst`의 client API·interface option과 `Documentation/driver-api/surface_aggregator/ssh.rst`의 protocol 설명을 먼저 익히는 것이 권장됩니다.

SSAM core 계층
serdevPacket Transport LayerPacket validation, ACK, retransmission
Packet Transport LayerRequest Transport LayerRequest/response matching, events
Request Transport LayerController LayerNotifier, completion, `SEQ`/`RQID`
Controller LayerClient Bus`ssam_device` and `ssam_device_driver`

낮은 전송 단위에서 client device model까지 책임을 단계적으로 확장합니다.

Overview
========

The SSAM core implementation is structured in layers, somewhat following the
SSH protocol structure:

Lower-level packet transport is implemented in the *packet transport layer
(PTL)*, directly building on top of the serial device (serdev)
infrastructure of the kernel. As the name indicates, this layer deals with
the packet transport logic and handles things like packet validation, packet
acknowledgment (ACKing), packet (retransmission) timeouts, and relaying
packet payloads to higher-level layers.

Above this sits the *request transport layer (RTL)*. This layer is centered
around command-type packet payloads, i.e. requests (sent from host to EC),
responses of the EC to those requests, and events (sent from EC to host).
It, specifically, distinguishes events from request responses, matches
responses to their corresponding requests, and implements request timeouts.

The *controller* layer is building on top of this and essentially decides
how request responses and, especially, events are dealt with. It provides an
event notifier system, handles event activation/deactivation, provides a
workqueue for event and asynchronous request completion, and also manages
the message counters required for building command messages (``SEQ``,
``RQID``). This layer basically provides a fundamental interface to the SAM
EC for use in other kernel drivers.

While the controller layer already provides an interface for other kernel
drivers, the client *bus* extends this interface to provide support for
native SSAM devices, i.e. devices that are not defined in ACPI and not
implemented as platform devices, via |ssam_device| and |ssam_device_driver|
simplify management of client devices and client drivers.

Refer to Documentation/driver-api/surface_aggregator/client.rst for
documentation regarding the client device/driver API and interface options
for other kernel drivers. It is recommended to familiarize oneself with
that chapter and the Documentation/driver-api/surface_aggregator/ssh.rst
before continuing with the architectural overview below.

Packet Transport Layer 개요

97-102

Packet transport layer는 `struct ssh_ptl`로 표현되며, 이어지는 packet, packet queue, pending set, transmitter·receiver thread, timeout reaper, locking 개념을 중심으로 구성됩니다.

PTL 핵심 구성
`ssh_packet`Packet QueueTransmitter Threadserdev
Sequenced packetPending SetACK or NAKCompletion or retry
Pending SetTimeout ReaperRetry or `-ETIMEDOUT`

Packet의 제출부터 ACK 또는 timeout 완료까지의 구성 요소입니다.

Packet Transport Layer
======================

The packet transport layer is represented via |ssh_ptl| and is structured
around the following key concepts:

Packet과 lifecycle

103-151

Packet은 SSH protocol의 기본 transmission unit입니다. SSAM core가 전송할 packet은 `struct ssh_packet`으로 표현되지만, core가 받은 packet은 별도 구조체 없이 raw `struct ssh_frame`으로만 관리됩니다.

`ssh_packet`에는 transport layer 내부 관리 field와 전송 data, 즉 `ssh_frame`으로 감싼 message가 든 buffer reference가 있습니다. Lifetime은 내부 reference count로 관리하며 `ssh_packet_get()`과 `ssh_packet_put()`으로 접근합니다.

Reference count가 0이 되면 `ssh_packet_ops`가 제공한 `release()` callback이 실행되어 packet 또는 이를 포함하는 `ssh_request` 같은 구조체를 해제할 수 있습니다.

`ssh_packet_ops`는 `complete()` callback도 제공합니다. 이 callback은 packet 완료 시 한 번 실행되며 성공이면 0, 오류이면 negative errno를 전달합니다. PTL에 제출된 packet은 성공·오류·취소 중 어느 결과든 `release()`보다 먼저 반드시 완료됩니다.

Packet state와 type은 `ssh_packet_flags`의 `state` bit로 관리합니다. `SSH_PACKET_SF_LOCKED_BIT`는 완료가 임박하여 새 reference를 만들면 안 되고 기존 reference도 가능한 한 빨리 놓아야 함을 뜻합니다. 이 bit를 설정한 process는 packet queue와 pending set의 reference를 제거할 책임이 있습니다.

`SSH_PACKET_SF_COMPLETED_BIT`는 `complete()`를 실행하는 process가 설정하여 callback이 한 번만 실행되도록 합니다. `SSH_PACKET_SF_QUEUED_BIT`와 `SSH_PACKET_SF_PENDING_BIT`는 각각 queue와 pending set에 추가될 때 설정되고 제거될 때 지워집니다.

주요 packet state bit
Bit설정 의미해제·책임
`SSH_PACKET_SF_LOCKED_BIT`Completion 임박, 새 reference 금지설정자가 queue와 pending reference 제거
`SSH_PACKET_SF_COMPLETED_BIT``complete()` 실행 중 또는 완료Callback 단일 실행 보장
`SSH_PACKET_SF_QUEUED_BIT`Packet queue에 있음Dequeue 시 clear
`SSH_PACKET_SF_PENDING_BIT`Pending set에 있음Set에서 제거할 때 clear

Packets
-------

Packets are the fundamental transmission unit of the SSH protocol. They are
managed by the packet transport layer, which is essentially the lowest layer
of the driver and is built upon by other components of the SSAM core.
Packets to be transmitted by the SSAM core are represented via |ssh_packet|
(in contrast, packets received by the core do not have any specific
structure and are managed entirely via the raw |ssh_frame|).

This structure contains the required fields to manage the packet inside the
transport layer, as well as a reference to the buffer containing the data to
be transmitted (i.e. the message wrapped in |ssh_frame|). Most notably, it
contains an internal reference count, which is used for managing its
lifetime (accessible via |ssh_packet_get| and |ssh_packet_put|). When this
counter reaches zero, the ``release()`` callback provided to the packet via
its |ssh_packet_ops| reference is executed, which may then deallocate the
packet or its enclosing structure (e.g. |ssh_request|).

In addition to the ``release`` callback, the |ssh_packet_ops| reference also
provides a ``complete()`` callback, which is run once the packet has been
completed and provides the status of this completion, i.e. zero on success
or a negative errno value in case of an error. Once the packet has been
submitted to the packet transport layer, the ``complete()`` callback is
always guaranteed to be executed before the ``release()`` callback, i.e. the
packet will always be completed, either successfully, with an error, or due
to cancellation, before it will be released.

The state of a packet is managed via its ``state`` flags
(|ssh_packet_flags|), which also contains the packet type. In particular,
the following bits are noteworthy:

* ``SSH_PACKET_SF_LOCKED_BIT``: This bit is set when completion, either
  through error or success, is imminent. It indicates that no further
  references of the packet should be taken and any existing references
  should be dropped as soon as possible. The process setting this bit is
  responsible for removing any references to this packet from the packet
  queue and pending set.

* ``SSH_PACKET_SF_COMPLETED_BIT``: This bit is set by the process running the
  ``complete()`` callback and is used to ensure that this callback only runs
  once.

* ``SSH_PACKET_SF_QUEUED_BIT``: This bit is set when the packet is queued on
  the packet queue and cleared when it is dequeued.

* ``SSH_PACKET_SF_PENDING_BIT``: This bit is set when the packet is added to
  the pending set and cleared when it is removed from it.

Packet Queue

152-164

Packet queue는 PTL의 두 기본 collection 중 첫 번째이며 priority queue입니다. Packet type이 major priority를, transmission try 수가 minor priority를 결정합니다. 구체적인 값은 `SSH_PACKET_PRIORITY`를 참조합니다.

PTL이 전송할 모든 packet은 `ssh_ptl_submit()`을 통해 이 queue에 제출해야 하며, PTL 자체가 보내는 control packet도 포함됩니다. Data packet은 timeout이나 EC가 보낸 NAK 때문에 내부적으로 다시 제출될 수 있습니다.

Packet queue priority
Packet typeMajor priority`SSH_PACKET_PRIORITY`
Number of triesMinor priority`SSH_PACKET_PRIORITY`
`ssh_ptl_submit()` or retryPriority QueueTransmitter Thread

Packet type과 retry 횟수를 합쳐 다음 전송 packet을 선택합니다.

Packet Queue
------------

The packet queue is the first of the two fundamental collections in the
packet transport layer. It is a priority queue, with priority of the
respective packets based on the packet type (major) and number of tries
(minor). See |SSH_PACKET_PRIORITY| for more details on the priority value.

All packets to be transmitted by the transport layer must be submitted to
this queue via |ssh_ptl_submit|. Note that this includes control packets
sent by the transport layer itself. Internally, data packets can be
re-submitted to this queue due to timeouts or NAK packets sent by the EC.

Packet Pending Set

165-176

Pending set은 PTL의 두 번째 기본 collection입니다. 이미 전송되었지만 EC의 acknowledgment, 예를 들어 대응 ACK packet을 기다리는 packet reference를 저장합니다.

Packet acknowledgment timeout이나 NAK로 다시 제출된 packet은 pending set에서 제거되지 않으므로 queued 상태와 pending 상태를 동시에 가질 수 있습니다.

Packet collection 상태 조합
QueuedPending의미
YesNo아직 전송되지 않은 packet
NoYes전송 후 ACK를 기다리는 packet
YesYesTimeout 또는 NAK로 재제출되어 ACK도 기다리는 packet

Pending Set
-----------

The pending set is the second of the two fundamental collections in the
packet transport layer. It stores references to packets that have already
been transmitted, but wait for acknowledgment (e.g. the corresponding ACK
packet) by the EC.

Note that a packet may both be pending and queued if it has been
re-submitted due to a packet acknowledgment timeout or NAK. On such a
re-submission, packets are not removed from the pending set.

Packet Transmitter Thread

177-197

Transmitter thread는 packet 전송의 실제 작업 대부분을 담당합니다. 매 iteration에서 queue의 다음 packet이 전송 가능한지 기다리고 확인한 뒤, 가능하면 dequeue하고 transmission attempt 수인 tries를 증가시킵니다.

EC의 ACK가 필요한 sequenced packet은 pending set에 추가한 다음 serdev subsystem에 data를 제출합니다. 제출 중 오류나 timeout이 발생하면 transmitter thread가 해당 status로 packet을 완료합니다.

ACK가 필요 없는 unsequenced packet은 transmitter thread에서 성공으로 완료됩니다.

동시에 ACK를 기다릴 수 있는 sequenced packet 수는 제한됩니다. 현재 제한은 1이며 이유는 `Documentation/driver-api/surface_aggregator/ssh.rst`에 설명되어 있습니다. ACK·NAK control packet은 이 제한과 무관하게 언제나 전송할 수 있습니다.

Transmitter iteration
Packet QueueCan transmit?Dequeue and increment triesserdev submission
SequencedAdd to Pending Setserdev submissionWait for ACK
Unsequencedserdev submissionComplete success
Submission error or timeoutComplete with error

Packet type에 따라 pending 등록과 완료 시점이 갈립니다.

Transmitter Thread
------------------

The transmitter thread is responsible for most of the actual work regarding
packet transmission. In each iteration, it (waits for and) checks if the
next packet on the queue (if any) can be transmitted and, if so, removes it
from the queue and increments its counter for the number of transmission
attempts, i.e. tries. If the packet is sequenced, i.e. requires an ACK by
the EC, the packet is added to the pending set. Next, the packet's data is
submitted to the serdev subsystem. In case of an error or timeout during
this submission, the packet is completed by the transmitter thread with the
status value of the callback set accordingly. In case the packet is
unsequenced, i.e. does not require an ACK by the EC, the packet is completed
with success on the transmitter thread.

Transmission of sequenced packets is limited by the number of concurrently
pending packets, i.e. a limit on how many packets may be waiting for an ACK
from the EC in parallel. This limit is currently set to one (see
Documentation/driver-api/surface_aggregator/ssh.rst for the reasoning behind
this). Control packets (i.e. ACK and NAK) can always be transmitted.

Packet Receiver Thread

198-218

EC에서 받은 모든 data는 추가 처리를 위해 FIFO buffer에 넣고 receiver thread가 처리합니다. 이 thread는 수신 message를 `ssh_frame`과 payload로 parse하고 validate하며, 유효한 message에는 필요한 ACK를, validation 오류나 잘못된 data에는 NAK를 준비해 제출합니다.

Receiver thread는 ACK의 sequence ID를 pending packet과 match하여 완료합니다. NAK를 받으면 현재 pending packet을 모두 다시 제출하기 시작하며, 이 재제출은 timeout에 의한 재제출과 비슷합니다.

Sequenced packet의 성공 completion은 항상 receiver thread에서 실행됩니다. 반면 실패를 나타내는 completion은 그 실패가 발생한 process에서 실행됩니다.

Payload data는 callback을 통해 바로 위의 request transport layer로 전달합니다.

Receiver 처리 경로
EC bytesFIFOReceiver ThreadParse and validate `ssh_frame`
Valid sequenced frameSubmit ACK
Invalid frameSubmit NAK
ACKMatch sequence IDComplete pending packet
NAKRe-submit all pending packets
PayloadData callbackRequest Transport Layer

수신 frame의 종류와 검증 결과에 따라 ACK·NAK·상위 전달이 결정됩니다.

Receiver Thread
---------------

Any data received from the EC is put into a FIFO buffer for further
processing. This processing happens on the receiver thread. The receiver
thread parses and validates the received message into its |ssh_frame| and
corresponding payload. It prepares and submits the necessary ACK (and on
validation error or invalid data NAK) packets for the received messages.

This thread also handles further processing, such as matching ACK messages
to the corresponding pending packet (via sequence ID) and completing it, as
well as initiating re-submission of all currently pending packets on
receival of a NAK message (re-submission in case of a NAK is similar to
re-submission due to timeout, see below for more details on that). Note that
the successful completion of a sequenced packet will always run on the
receiver thread (whereas any failure-indicating completion will run on the
process where the failure occurred).

Any payload data is forwarded via a callback to the next upper layer, i.e.
the request transport layer.

Packet Timeout Reaper

219-245

Packet acknowledgment timeout은 sequenced packet마다 존재합니다. 각 transmission attempt가 transmitter thread에서 시작될 때 한 번 arm되며, timeout 시 packet을 다시 제출하거나 tries가 한도를 넘었다면 취소합니다.

전용 reaper task는 다음 packet의 timeout 시점에 실행되도록 반복 schedule되는 work item입니다. 실행되면 pending set에서 timeout을 넘긴 packet을 찾고, 남은 packet이 있으면 다음 적절한 시점으로 자신을 다시 schedule합니다.

Timeout packet에 try가 남아 있으면 재제출하고, 없으면 status `-ETIMEDOUT`으로 완료합니다. Timeout이나 NAK에 의한 재제출은 tries가 증가한 packet을 queue에 추가하므로 priority가 높아집니다.

재제출된 packet은 다음 transmission attempt 전까지 timeout이 disable되며 pending set에는 계속 남습니다.

Transmission timeout과 packet acknowledgment timeout 덕분에 PTL은 packet을 timeout시키는 방식으로라도 항상 진행하며 완전히 block되지 않습니다.

Packet timeout reaper
Transmission attemptArm per-packet ACK timeoutPending Set
Reaper at next expirationScan expired packetsTries left?
Tries leftDisable timeoutIncrement triesQueue with higher priority
No tries leftComplete `-ETIMEDOUT`
Remaining pending packetsSchedule next expiration

Pending packet의 기한과 남은 try에 따라 retry 또는 최종 완료를 선택합니다.

Timeout Reaper
--------------

The packet acknowledgment timeout is a per-packet timeout for sequenced
packets, started when the respective packet begins (re-)transmission (i.e.
this timeout is armed once per transmission attempt on the transmitter
thread). It is used to trigger re-submission or, when the number of tries
has been exceeded, cancellation of the packet in question.

This timeout is handled via a dedicated reaper task, which is essentially a
work item (re-)scheduled to run when the next packet is set to time out. The
work item then checks the set of pending packets for any packets that have
exceeded the timeout and, if there are any remaining packets, re-schedules
itself to the next appropriate point in time.

If a timeout has been detected by the reaper, the packet will either be
re-submitted if it still has some remaining tries left, or completed with
``-ETIMEDOUT`` as status if not. Note that re-submission, in this case and
triggered by receival of a NAK, means that the packet is added to the queue
with a now incremented number of tries, yielding a higher priority. The
timeout for the packet will be disabled until the next transmission attempt
and the packet remains on the pending set.

Note that due to transmission and packet acknowledgment timeouts, the packet
transport layer is always guaranteed to make progress, if only through
timing out packets, and will never fully block.

PTL concurrency와 locking

246-287

PTL에는 packet queue와 pending set을 각각 보호하는 두 main lock이 있습니다. 각 collection은 대응 lock을 잡은 동안에만 접근·수정할 수 있습니다. 두 collection을 모두 접근하려면 deadlock을 피하도록 pending lock을 먼저, queue lock을 나중에 획득해야 합니다.

최초 제출 뒤 packet priority는 queue lock을 보유할 때만, packet timestamp는 pending lock을 보유할 때만 접근할 수 있습니다.

State flag는 atomic bit operation과 필요 시 memory barrier로 관리합니다. Timeout reaper work item과 expiration date 변경은 별도 lock이 보호합니다.

Packet의 PTL reference인 `ptl`은 상위 request 제출 때, 상위 request가 없으면 packet 최초 제출 때 설정되고 이후 바뀌지 않습니다. Cancellation처럼 제출과 동시에 실행될 수 있는 function은 `ptl`이 이미 설정되었다고 가정할 수 없으므로 `READ_ONCE()`로 읽고 대칭적으로 `WRITE_ONCE()`로 설정합니다.

Tracing을 위한 priority와 state는 stale value가 치명적이지 않은 read-only 상황에서만 대응 lock 밖에서 읽을 수 있으며, 이때도 `WRITE_ONCE()`와 `READ_ONCE()`로 접근을 보장합니다.

상위 interface의 `ssh_ptl_submit()`, `ssh_ptl_cancel()`, `ssh_ptl_rx_rcvbuf()`, `ssh_ptl_shutdown()`은 서로 동시에 실행할 수 있습니다. 다만 같은 packet에 대한 submit은 자기 자신과 동시에 실행할 수 없고, shutdown과 data receive도 각각 자기 자신과 동시에 실행할 수는 없지만 서로 간에는 병행할 수 있습니다.

PTL lock과 concurrency 계약
대상보호·제약
Packet QueueQueue lock; priority도 이 lock 아래 접근
Pending SetPending lock; timestamp도 이 lock 아래 접근
두 collectionPending lock을 queue lock보다 먼저 획득
State flagsAtomic bit operations and memory barriers
Timeout reaper전용 lock
`ptl`, trace reads`WRITE_ONCE()` and `READ_ONCE()`

Concurrency and Locking
-----------------------

There are two main locks in the packet transport layer: One guarding access
to the packet queue and one guarding access to the pending set. These
collections may only be accessed and modified under the respective lock. If
access to both collections is needed, the pending lock must be acquired
before the queue lock to avoid deadlocks.

In addition to guarding the collections, after initial packet submission
certain packet fields may only be accessed under one of the locks.
Specifically, the packet priority must only be accessed while holding the
queue lock and the packet timestamp must only be accessed while holding the
pending lock.

Other parts of the packet transport layer are guarded independently. State
flags are managed by atomic bit operations and, if necessary, memory
barriers. Modifications to the timeout reaper work item and expiration date
are guarded by their own lock.

The reference of the packet to the packet transport layer (``ptl``) is
somewhat special. It is either set when the upper layer request is submitted
or, if there is none, when the packet is first submitted. After it is set,
it will not change its value. Functions that may run concurrently with
submission, i.e. cancellation, can not rely on the ``ptl`` reference to be
set. Access to it in these functions is guarded by ``READ_ONCE()``, whereas
setting ``ptl`` is equally guarded with ``WRITE_ONCE()`` for symmetry.

Some packet fields may be read outside of the respective locks guarding
them, specifically priority and state for tracing. In those cases, proper
access is ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``. Such
read-only access is only allowed when stale values are not critical.

With respect to the interface for higher layers, packet submission
(|ssh_ptl_submit|), packet cancellation (|ssh_ptl_cancel|), data receival
(|ssh_ptl_rx_rcvbuf|), and layer shutdown (|ssh_ptl_shutdown|) may always be
executed concurrently with respect to each other. Note that packet
submission may not run concurrently with itself for the same packet.
Equally, shutdown and data receival may also not run concurrently with
themselves (but may run concurrently with each other).

Request Transport Layer 개요

288-299

Request transport layer는 `struct ssh_rtl`로 표현되며 PTL 위에 구축됩니다. Host가 보내는 `ssh_command` payload의 SSH packet을 request로 다룹니다.

EC도 `ssh_command` payload로 보내는 request response와 event를 이 계층에서 구분합니다. Response는 RTL이 처리하고 event는 callback을 통해 바로 위 controller layer로 전달합니다.

RTL 입력 분류
Host `ssh_command`RequestPacket Transport LayerEC
EC `ssh_command`Request ID classificationResponse handling in RTL
EC `ssh_command`Event IDController callback

같은 command-type payload를 request response와 event로 구분합니다.

Request Transport Layer
=======================

The request transport layer is represented via |ssh_rtl| and builds on top
of the packet transport layer. It deals with requests, i.e. SSH packets sent
by the host containing a |ssh_command| as frame payload. This layer
separates responses to requests from events, which are also sent by the EC
via a |ssh_command| payload. While responses are handled in this layer,
events are relayed to the next upper layer, i.e. the controller layer, via
the corresponding callback. The request transport layer is structured around
the following key concepts:

Request와 lifecycle

300-355

Request는 data를 query하거나 action을 trigger하거나 둘 다 수행하도록 host에서 EC로 보내는 command-type payload packet입니다. `struct ssh_request`가 message data를 담은 내부 `ssh_packet`을 감싸며 `ssam_request_sync` 같은 모든 top-level 표현도 이 구조체 위에 구축됩니다.

`ssh_request`가 `ssh_packet`을 확장하므로 lifetime도 packet 내부 reference counter로 관리하고 `ssh_request_get()`과 `ssh_request_put()`으로 접근합니다. Counter가 0이 되면 request의 `ssh_request_ops`가 제공한 `release()` callback을 호출합니다.

Request에는 EC가 command-type SSH message로 보내는 optional response가 있을 수 있습니다. Request를 만드는 쪽은 response 예상 여부를 알아야 하며 `ssh_request_init()`에 전달하는 request flag에 표시하여 RTL이 response를 기다리게 해야 합니다.

Request ops의 `complete()` callback도 RTL에 `ssh_rtl_submit()`으로 제출한 뒤 release보다 먼저 반드시 실행됩니다. Response가 없는 request는 내부 packet이 PTL에서 성공적으로 전송되면 packet completion callback 안에서 성공 완료됩니다.

Response가 있는 request는 receiver thread에서 실행되는 packet layer data-received callback이 request ID로 response를 match한 뒤 성공 완료됩니다. Error completion이면 status는 대응 negative errno입니다.

Request type과 state는 `ssh_request_flags`로 관리합니다. `SSH_REQUEST_SF_LOCKED_BIT`는 완료 임박과 새 reference 금지를 나타내며 설정자가 request queue와 pending set의 reference를 제거해야 합니다.

`SSH_REQUEST_SF_COMPLETED_BIT`는 `complete()`가 한 번만 실행되도록 하고, `SSH_REQUEST_SF_QUEUED_BIT`와 `SSH_REQUEST_SF_PENDING_BIT`는 각각 queue와 pending set membership을 나타냅니다.

Request 완료 경로와 state
조건·bit동작
No response expectedUnderlying packet 성공 시 request 완료
Response expectedRQID match 후 request 완료
ErrorNegative errno로 완료
`SSH_REQUEST_SF_LOCKED_BIT`완료 임박, queue·pending reference 제거
`SSH_REQUEST_SF_COMPLETED_BIT`Callback 단일 실행
`SSH_REQUEST_SF_QUEUED_BIT` / `PENDING_BIT`Collection membership

Request
-------

Requests are packets with a command-type payload, sent from host to EC to
query data from or trigger an action on it (or both simultaneously). They
are represented by |ssh_request|, wrapping the underlying |ssh_packet|
storing its message data (i.e. SSH frame with command payload). Note that
all top-level representations, e.g. |ssam_request_sync| are built upon this
struct.

As |ssh_request| extends |ssh_packet|, its lifetime is also managed by the
reference counter inside the packet struct (which can be accessed via
|ssh_request_get| and |ssh_request_put|). Once the counter reaches zero, the
``release()`` callback of the |ssh_request_ops| reference of the request is
called.

Requests can have an optional response that is equally sent via a SSH
message with command-type payload (from EC to host). The party constructing
the request must know if a response is expected and mark this in the request
flags provided to |ssh_request_init|, so that the request transport layer
can wait for this response.

Similar to |ssh_packet|, |ssh_request| also has a ``complete()`` callback
provided via its request ops reference and is guaranteed to be completed
before it is released once it has been submitted to the request transport
layer via |ssh_rtl_submit|. For a request without a response, successful
completion will occur once the underlying packet has been successfully
transmitted by the packet transport layer (i.e. from within the packet
completion callback). For a request with response, successful completion
will occur once the response has been received and matched to the request
via its request ID (which happens on the packet layer's data-received
callback running on the receiver thread). If the request is completed with
an error, the status value will be set to the corresponding (negative) errno
value.

The state of a request is again managed via its ``state`` flags
(|ssh_request_flags|), which also encode the request type. In particular,
the following bits are noteworthy:

* ``SSH_REQUEST_SF_LOCKED_BIT``: This bit is set when completion, either
  through error or success, is imminent. It indicates that no further
  references of the request should be taken and any existing references
  should be dropped as soon as possible. The process setting this bit is
  responsible for removing any references to this request from the request
  queue and pending set.

* ``SSH_REQUEST_SF_COMPLETED_BIT``: This bit is set by the process running the
  ``complete()`` callback and is used to ensure that this callback only runs
  once.

* ``SSH_REQUEST_SF_QUEUED_BIT``: This bit is set when the request is queued on
  the request queue and cleared when it is dequeued.

* ``SSH_REQUEST_SF_PENDING_BIT``: This bit is set when the request is added to
  the pending set and cleared when it is removed from it.

Request Queue

356-370

Request queue는 RTL의 두 기본 collection 중 첫 번째입니다. PTL packet queue와 달리 priority queue가 아니며 단순한 first come first serve 원칙을 따릅니다.

RTL이 전송할 모든 request는 `ssh_rtl_submit()`을 통해 이 queue에 제출합니다. 한 번 제출한 request는 다시 제출할 수 없고 timeout 때 자동 재제출되지 않으며 timeout error로 완료됩니다.

다시 시도하려면 caller가 새 request를 만들어 제출해야 하며 같은 request instance를 다시 제출해서는 안 됩니다.

Request queue retry 계약
New request`ssh_rtl_submit()`FIFO Request QueueTransmitter Task
TimeoutComplete with timeout error
Caller wants retryConstruct new request`ssh_rtl_submit()`
Same request re-submitForbidden

Request instance는 단 한 번만 제출할 수 있습니다.

Request Queue
-------------

The request queue is the first of the two fundamental collections in the
request transport layer. In contrast to the packet queue of the packet
transport layer, it is not a priority queue and the simple first come first
serve principle applies.

All requests to be transmitted by the request transport layer must be
submitted to this queue via |ssh_rtl_submit|. Once submitted, requests may
not be re-submitted, and will not be re-submitted automatically on timeout.
Instead, the request is completed with a timeout error. If desired, the
caller can create and submit a new request for another try, but it must not
submit the same request again.

Request Pending Set

371-378

Pending set은 RTL의 두 번째 기본 collection입니다. EC response를 기다리는 모든 pending request의 reference를 저장하며, PTL pending set이 ACK를 기다리는 packet을 저장하는 것과 유사합니다.

두 pending set의 차이
계층저장 대상기다리는 것
Packet Transport LayerSequenced packet referenceEC ACK
Request Transport LayerResponse-bearing request referenceEC response

Pending Set
-----------

The pending set is the second of the two fundamental collections in the
request transport layer. This collection stores references to all pending
requests, i.e. requests awaiting a response from the EC (similar to what the
pending set of the packet transport layer does for packets).

Request Transmitter Task

379-389

새 request가 전송 가능해지면 transmitter task가 schedule됩니다. Queue의 다음 request를 전송할 수 있는지 검사하고 가능하면 내부 packet을 PTL에 제출합니다.

이 검사는 동시에 response를 기다리는 pending request 수를 제한합니다. Response가 필요한 request는 packet을 제출하기 전에 pending set에 먼저 추가합니다.

RTL transmitter task
New queued requestSchedule transmitter taskPending capacity available?
Response expectedAdd request to Pending SetSubmit underlying packet to PTL
No response expectedSubmit underlying packet to PTL

Pending limit을 확인한 뒤 response 필요 여부에 따라 set 등록 순서를 지킵니다.

Transmitter Task
----------------

The transmitter task is scheduled when a new request is available for
transmission. It checks if the next request on the request queue can be
transmitted and, if so, submits its underlying packet to the packet
transport layer. This check ensures that only a limited number of
requests can be pending, i.e. waiting for a response, at the same time. If
the request requires a response, the request is added to the pending set
before its packet is submitted.

Packet Completion Callback

390-402

Request의 내부 packet이 완료되면 packet completion callback이 실행됩니다. Packet이 error로 완료되면 request도 callback에 제공된 error 값으로 완료됩니다.

Packet이 성공한 뒤의 처리는 request 유형에 달립니다. Response를 기다리는 request는 transmitted 상태로 표시하고 request timeout을 시작합니다. Response가 필요 없는 request는 즉시 성공 완료합니다.

Packet completion에서 request 처리
Underlying packet completionErrorComplete request with error
Underlying packet successResponse expectedMark transmittedStart request timeout
Underlying packet successNo responseComplete request success

내부 packet 결과와 response 기대 여부가 request의 다음 상태를 결정합니다.

Packet Completion Callback
--------------------------

The packet completion callback is executed once the underlying packet of a
request has been completed. In case of an error completion, the
corresponding request is completed with the error value provided in this
callback.

On successful packet completion, further processing depends on the request.
If the request expects a response, it is marked as transmitted and the
request timeout is started. If the request does not expect a response, it is
completed with success.

Data-Received Callback

403-416

Data-received callback은 내부 PTL이 data-type frame을 받았다고 RTL에 알립니다. 일반적으로 payload는 command type이어야 합니다.

Command의 request ID가 event에 예약된 1부터 `SSH_NUM_EVENTS`까지의 범위라면 RTL에 등록된 event callback으로 전달합니다.

Request ID가 request response를 나타내면 pending set에서 대응 request를 찾습니다. Request가 존재하고 transmitted로 표시되어 있으면 성공으로 완료합니다.

수신 command의 RQID 분류
Data-type frameCommand payloadInspect request ID
RQID 1..`SSH_NUM_EVENTS`Registered event callbackController Layer
Response RQIDLookup Pending SetFound and transmittedComplete success

RQID가 event 예약 범위인지 request response인지에 따라 전달 목적지가 달라집니다.

Data-Received Callback
----------------------

The data received callback notifies the request transport layer of data
being received by the underlying packet transport layer via a data-type
frame. In general, this is expected to be a command-type payload.

If the request ID of the command is one of the request IDs reserved for
events (one to ``SSH_NUM_EVENTS``, inclusively), it is forwarded to the
event callback registered in the request transport layer. If the request ID
indicates a response to a request, the respective request is looked up in
the pending set and, if found and marked as transmitted, completed with
success.

Request Timeout Reaper

417-436

Request-response timeout은 response를 기대하는 request마다 존재하여 EC response를 무한히 기다리지 않게 합니다. 내부 packet이 성공적으로 완료된 뒤 시작됩니다.

PTL의 packet acknowledgment timeout과 마찬가지로, 다음 request의 timeout 시점에 실행되도록 반복 schedule되는 전용 reaper work item이 처리합니다.

Reaper는 pending request set을 scan하여 timeout된 request를 status `-ETIMEDOUT`으로 완료합니다. Request는 자동 재제출되지 않으며 필요하면 발행자가 새 request를 만들어 제출해야 합니다.

이 timeout은 packet transmission·acknowledgment timeout과 함께 RTL이 request나 packet을 timeout시키는 방식으로라도 계속 진행하고 완전히 block되지 않도록 보장합니다.

Request timeout reaper
Underlying packet successStart request-response timeoutPending Set
Reaper at next expirationScan timed-out requestsComplete `-ETIMEDOUT`
Retry desiredIssuer constructs a new request
Remaining requestsSchedule next expiration

성공적으로 전송됐지만 response가 오지 않은 request를 최종 완료합니다.

Timeout Reaper
--------------

The request-response-timeout is a per-request timeout for requests expecting
a response. It is used to ensure that a request does not wait indefinitely
on a response from the EC and is started after the underlying packet has
been successfully completed.

This timeout is, similar to the packet acknowledgment timeout on the packet
transport layer, handled via a dedicated reaper task. This task is
essentially a work-item (re-)scheduled to run when the next request is set
to time out. The work item then scans the set of pending requests for any
requests that have timed out and completes them with ``-ETIMEDOUT`` as
status. Requests will not be re-submitted automatically. Instead, the issuer
of the request must construct and submit a new request, if so desired.

Note that this timeout, in combination with packet transmission and
acknowledgment timeouts, guarantees that the request layer will always make
progress, even if only through timing out packets, and never fully block.

RTL concurrency와 locking

437-462

RTL도 request queue와 pending set을 각각 보호하는 두 main lock을 둡니다. 각 collection은 대응 lock을 보유한 동안에만 접근하거나 수정할 수 있습니다.

State flag는 atomic bit operation과 필요 시 memory barrier로 관리하고, timeout reaper work item과 expiration date 변경은 별도 lock으로 보호합니다.

Tracing을 위해 state를 lock 밖에서 읽을 때는 stale value가 치명적이지 않은 read-only 상황에서만 허용하며 `WRITE_ONCE()`와 `READ_ONCE()`를 사용합니다.

상위 interface의 `ssh_rtl_submit()`, `ssh_rtl_cancel()`, `ssh_rtl_shutdown()`은 서로 동시에 실행할 수 있습니다. 다만 같은 request의 submit은 자기 자신과 동시에 실행할 수 없고 request마다 한 번만 호출할 수 있습니다. Shutdown도 자기 자신과 동시에 실행할 수 없습니다.

RTL 동시성 계약
대상계약
Request QueueQueue lock 아래 접근·수정
Pending SetPending lock 아래 접근·수정
State flagsAtomic bit operations and memory barriers
Timeout reaper전용 lock
Trace state read`WRITE_ONCE()` and `READ_ONCE()`; stale 허용 시만
SubmitRequest당 한 번, 동일 request 동시 submit 금지

Concurrency and Locking
-----------------------

Similar to the packet transport layer, there are two main locks in the
request transport layer: One guarding access to the request queue and one
guarding access to the pending set. These collections may only be accessed
and modified under the respective lock.

Other parts of the request transport layer are guarded independently. State
flags are (again) managed by atomic bit operations and, if necessary, memory
barriers. Modifications to the timeout reaper work item and expiration date
are guarded by their own lock.

Some request fields may be read outside of the respective locks guarding
them, specifically the state for tracing. In those cases, proper access is
ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``. Such read-only
access is only allowed when stale values are not critical.

With respect to the interface for higher layers, request submission
(|ssh_rtl_submit|), request cancellation (|ssh_rtl_cancel|), and layer
shutdown (|ssh_rtl_shutdown|) may always be executed concurrently with
respect to each other. Note that request submission may not run concurrently
with itself for the same request (and also may only be called once per
request). Equally, shutdown may also not run concurrently with itself.

Controller Layer

463-473

Controller layer는 RTL을 확장하여 client driver가 사용하기 쉬운 interface를 제공합니다. `struct ssam_controller`와 SSH driver로 표현됩니다.

하위 transport layer가 packet과 request의 전송·처리를 담당하는 반면 controller는 관리 역할을 맡습니다. Device initialization, power management, event delivery와 registration을 포함한 event handling을 event completion system인 `ssam_cplt`를 통해 처리합니다.

Controller 관리 책임
Packet Transport LayerRequest Transport LayerController Layer
Controller LayerDevice initialization
Controller LayerPower management
Controller Layer`ssam_cplt`Event registration and delivery

전송 primitive 위에 device와 event lifecycle을 제공합니다.

Controller Layer
================

The controller layer extends on the request transport layer to provide an
easy-to-use interface for client drivers. It is represented by
|ssam_controller| and the SSH driver. While the lower level transport layers
take care of transmitting and handling packets and requests, the controller
layer takes on more of a management role. Specifically, it handles device
initialization, power management, and event handling, including event
delivery and registration via the (event) completion system (|ssam_cplt|).

Event Registration

474-513

일반적으로 host가 event 또는 event class를 명시적으로 요청해야 EC가 보냅니다. HID input event는 예외로 보입니다. Event-enable request로 활성화하고 더 이상 필요 없으면 event-disable request로 비활성화해야 합니다.

Event를 enable·disable하는 구체적인 request는 event의 관리 주체에 해당하는 `ssam_event_registry`가 정합니다. Request parameter로 target category와 registry에 따라 instance ID를 제공합니다. Registry가 instance ID를 쓰지 않으면 0이어야 합니다.

Target category와 optional instance ID가 `ssam_event_id`를 구성합니다. Event registry와 event ID를 함께 사용해야 event class를 고유하게 식별할 수 있습니다.

Enable-event request에는 별도의 request ID parameter도 필요합니다. 이 값은 활성화할 event class를 바꾸지 않고 EC가 보내는 해당 class의 모든 event에 RQID로 기록됩니다.

Event 식별용 request ID는 1부터 `SSH_NUM_EVENTS`까지로 제한되어 event 여부와 구체적인 class mapping에 사용됩니다. 현재 controller는 `ssam_event_id`의 target category를 이 parameter로 항상 설정합니다.

여러 client driver가 같거나 겹치는 event class를 사용할 수 있지만 enable·disable call은 on/off의 binary operation입니다. Controller는 event registry와 ID를 key로 하는 RB-tree mapping에 reference count를 저장하여 access를 조정합니다. 유효한 registry·ID 조합의 알려진 전체 목록은 없습니다.

자세한 reference count 동작은 `ssam_nf`, `ssam_nf_refcount_inc()`, `ssam_nf_refcount_dec()`를 참조합니다. 이 관리는 다음 절의 notifier registration과 함께 top-level `ssam_notifier_register()`·`ssam_notifier_unregister()`에서 수행됩니다.

Event class 식별과 활성화
요소역할
`ssam_event_registry`Enable/disable request를 정하는 관리 주체
Target categoryEvent ID의 필수 부분
Instance IDRegistry가 사용하지 않으면 0
`ssam_event_id`Target category와 instance ID 결합
Enable request RQIDEvent 표시와 class mapping; 현재 target category 사용
RB-tree refcount겹치는 client 요청을 binary enable/disable에 맞게 조정

Event Registration
------------------

In general, an event (or rather a class of events) has to be explicitly
requested by the host before the EC will send it (HID input events seem to
be the exception). This is done via an event-enable request (similarly,
events should be disabled via an event-disable request once no longer
desired).

The specific request used to enable (or disable) an event is given via an
event registry, i.e. the governing authority of this event (so to speak),
represented by |ssam_event_registry|. As parameters to this request, the
target category and, depending on the event registry, instance ID of the
event to be enabled must be provided. This (optional) instance ID must be
zero if the registry does not use it. Together, target category and instance
ID form the event ID, represented by |ssam_event_id|. In short, both, event
registry and event ID, are required to uniquely identify a respective class
of events.

Note that a further *request ID* parameter must be provided for the
enable-event request. This parameter does not influence the class of events
being enabled, but instead is set as the request ID (RQID) on each event of
this class sent by the EC. It is used to identify events (as a limited
number of request IDs is reserved for use in events only, specifically one
to ``SSH_NUM_EVENTS`` inclusively) and also map events to their specific
class. Currently, the controller always sets this parameter to the target
category specified in |ssam_event_id|.

As multiple client drivers may rely on the same (or overlapping) classes of
events and enable/disable calls are strictly binary (i.e. on/off), the
controller has to manage access to these events. It does so via reference
counting, storing the counter inside an RB-tree based mapping with event
registry and ID as key (there is no known list of valid event registry and
event ID combinations). See |ssam_nf|, |ssam_nf_refcount_inc|, and
|ssam_nf_refcount_dec| for details.

This management is done together with notifier registration (described in
the next section) via the top-level |ssam_notifier_register| and
|ssam_notifier_unregister| functions.

Event Delivery

514-552

Client driver가 event를 받으려면 `ssam_notifier_register()`로 event notifier를 등록해야 합니다. 이 함수는 해당 event class의 reference counter를 증가시키고, 아직 활성화되지 않았다면 EC에서 class를 enable한 뒤 notifier callback을 설치합니다.

Notifier callback은 target category마다 하나씩 존재하는 RCU list에 저장됩니다. Target category 수는 고정되어 알려져 있습니다.

Event registry와 event ID 조합에서 event class가 제공할 command data인 target ID, target category, command ID, instance ID를 모두 알아내는 알려진 association은 없습니다. Event ID가 제공하는 target category와 instance ID만 알 수 있습니다.

Notifier 저장 방식 때문에 client driver는 요청하지 않은 event도 받을 수 있으며 이를 처리해야 합니다. 기본적으로 같은 target category의 모든 event를 받습니다.

이를 단순화하도록 notifier 등록 시 event registry의 target ID와 event ID의 instance ID를 기준으로 filtering을 요청할 수 있습니다. Filter는 callback 실행 시 notifier list를 순회하면서 적용합니다.

모든 notifier callback은 completion workqueue라는 전용 workqueue에서 실행됩니다. PTL receiver thread에서 실행되는 RTL callback이 event를 받으면 대응 `ssam_event_queue`에 넣습니다. 그 queue의 completion work item이 completion workqueue에서 event를 꺼내 notifier callback을 실행하므로 receiver thread를 block하지 않습니다.

Target ID와 target category 조합마다 event queue가 하나씩 있습니다. 같은 조합의 event callback은 순서대로 실행하고, 조합이 다른 event callback은 병렬로 실행할 수 있습니다.

Event delivery와 ordering
EC eventPTL Receiver ThreadRTL event callback`ssam_event_queue`
Target ID + target categoryDedicated event queueCompletion work item
Completion WorkqueueApply target/instance filtersNotifier callbacks in order
Different target/categoryDifferent queuesCallbacks may run in parallel

Receiver thread는 enqueue까지만 수행하고 callback은 completion workqueue가 실행합니다.

Event Delivery
--------------

To receive events, a client driver has to register an event notifier via
|ssam_notifier_register|. This increments the reference counter for that
specific class of events (as detailed in the previous section), enables the
class on the EC (if it has not been enabled already), and installs the
provided notifier callback.

Notifier callbacks are stored in lists, with one (RCU) list per target
category (provided via the event ID; NB: there is a fixed known number of
target categories). There is no known association from the combination of
event registry and event ID to the command data (target ID, target category,
command ID, and instance ID) that can be provided by an event class, apart
from target category and instance ID given via the event ID.

Note that due to the way notifiers are (or rather have to be) stored, client
drivers may receive events that they have not requested and need to account
for them. Specifically, they will, by default, receive all events from the
same target category. To simplify dealing with this, filtering of events by
target ID (provided via the event registry) and instance ID (provided via
the event ID) can be requested when registering a notifier. This filtering
is applied when iterating over the notifiers at the time they are executed.

All notifier callbacks are executed on a dedicated workqueue, the so-called
completion workqueue. After an event has been received via the callback
installed in the request layer (running on the receiver thread of the packet
transport layer), it will be put on its respective event queue
(|ssam_event_queue|). From this event queue the completion work item of that
queue (running on the completion workqueue) will pick up the event and
execute the notifier callback. This is done to avoid blocking on the
receiver thread.

There is one event queue per combination of target ID and target category.
This is done to ensure that notifier callbacks are executed in sequence for
events of the same target ID and target category. Callbacks can be executed
in parallel for events with a different combination of target ID and target
category.

Controller concurrency와 locking

553-578

Controller의 concurrency safety 대부분은 하위 RTL이 제공합니다. 여기에 event 등록·해제를 보호하는 별도 lock이 추가됩니다.

Controller state 접근은 read/write semaphore인 state lock이 보호합니다. Reader 쪽은 state가 유지되어야 하는 function을 실행하는 동안 state가 바뀌지 않음을 보장합니다.

이 reader 보장은 `ssam_notifier_register()`, `ssam_notifier_unregister()`, `ssam_request_sync_submit()` 및 파생 function에 필요하며, `ssam_client_bind()`나 `ssam_client_link()`가 이미 같은 보장을 제공하는 경우에는 중복해서 필요하지 않습니다.

Writer 쪽은 initialization, destruction, suspension, resumption처럼 state를 바꾸는 모든 transition을 보호합니다.

잘못된 API 사용을 smoke-test하기 위해 `ssam_request_sync_submit()` 등에서 state lock 밖의 controller state를 read-only로 확인할 수 있습니다. 이 검사는 모든 잘못된 사용을 막는 동기화 장치가 아니라 발견을 돕는 진단이며 `WRITE_ONCE()`와 `READ_ONCE()`로 variable 접근을 보장합니다.

State가 변하지 않아야 한다는 precondition을 만족했다면 initialization과 shutdown을 제외한 모든 function은 서로 동시에 실행할 수 있습니다. 여기에는 `ssam_notifier_register()`, `ssam_notifier_unregister()`, `ssam_request_sync_submit()` 및 그 위에 구축된 모든 function이 포함됩니다.

Controller lock 체계
Lock·접근보장
Event registration lockNotifier 등록·해제 직렬화
State lock readerOperation 동안 controller state 유지
State lock writerInit, destroy, suspend, resume transition
`ssam_client_bind()` / `ssam_client_link()`일부 state-stability 보장을 이미 제공
Lockless smoke test`WRITE_ONCE()` / `READ_ONCE()`; 진단 목적

Concurrency and Locking
-----------------------

Most of the concurrency related safety guarantees of the controller are
provided by the lower-level request transport layer. In addition to this,
event (un-)registration is guarded by its own lock.

Access to the controller state is guarded by the state lock. This lock is a
read/write semaphore. The reader part can be used to ensure that the state
does not change while functions depending on the state to stay the same
(e.g. |ssam_notifier_register|, |ssam_notifier_unregister|,
|ssam_request_sync_submit|, and derivatives) are executed and this guarantee
is not already provided otherwise (e.g. through |ssam_client_bind| or
|ssam_client_link|). The writer part guards any transitions that will change
the state, i.e. initialization, destruction, suspension, and resumption.

The controller state may be accessed (read-only) outside the state lock for
smoke-testing against invalid API usage (e.g. in |ssam_request_sync_submit|).
Note that such checks are not supposed to (and will not) protect against all
invalid usages, but rather aim to help catch them. In those cases, proper
variable access is ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``.

Assuming any preconditions on the state not changing have been satisfied,
all non-initialization and non-shutdown functions may run concurrently with
each other. This includes |ssam_notifier_register|, |ssam_notifier_unregister|,
|ssam_request_sync_submit|, as well as all functions building on top of those.