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