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