579 lines · plain
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 Internals46=====================47 48Architectural overview of the Surface System Aggregator Module (SSAM) core49and Surface Serial Hub (SSH) driver. For the API documentation, refer to:50 51.. toctree::52 :maxdepth: 253 54 internal-api55 56 57Overview58========59 60The SSAM core implementation is structured in layers, somewhat following the61SSH protocol structure:62 63Lower-level packet transport is implemented in the *packet transport layer64(PTL)*, directly building on top of the serial device (serdev)65infrastructure of the kernel. As the name indicates, this layer deals with66the packet transport logic and handles things like packet validation, packet67acknowledgment (ACKing), packet (retransmission) timeouts, and relaying68packet payloads to higher-level layers.69 70Above this sits the *request transport layer (RTL)*. This layer is centered71around 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, matches74responses to their corresponding requests, and implements request timeouts.75 76The *controller* layer is building on top of this and essentially decides77how request responses and, especially, events are dealt with. It provides an78event notifier system, handles event activation/deactivation, provides a79workqueue for event and asynchronous request completion, and also manages80the message counters required for building command messages (``SEQ``,81``RQID``). This layer basically provides a fundamental interface to the SAM82EC for use in other kernel drivers.83 84While the controller layer already provides an interface for other kernel85drivers, the client *bus* extends this interface to provide support for86native SSAM devices, i.e. devices that are not defined in ACPI and not87implemented as platform devices, via |ssam_device| and |ssam_device_driver|88simplify management of client devices and client drivers.89 90Refer to Documentation/driver-api/surface_aggregator/client.rst for91documentation regarding the client device/driver API and interface options92for other kernel drivers. It is recommended to familiarize oneself with93that chapter and the Documentation/driver-api/surface_aggregator/ssh.rst94before continuing with the architectural overview below.95 96 97Packet Transport Layer98======================99 100The packet transport layer is represented via |ssh_ptl| and is structured101around the following key concepts:102 103Packets104-------105 106Packets are the fundamental transmission unit of the SSH protocol. They are107managed by the packet transport layer, which is essentially the lowest layer108of the driver and is built upon by other components of the SSAM core.109Packets to be transmitted by the SSAM core are represented via |ssh_packet|110(in contrast, packets received by the core do not have any specific111structure and are managed entirely via the raw |ssh_frame|).112 113This structure contains the required fields to manage the packet inside the114transport layer, as well as a reference to the buffer containing the data to115be transmitted (i.e. the message wrapped in |ssh_frame|). Most notably, it116contains an internal reference count, which is used for managing its117lifetime (accessible via |ssh_packet_get| and |ssh_packet_put|). When this118counter reaches zero, the ``release()`` callback provided to the packet via119its |ssh_packet_ops| reference is executed, which may then deallocate the120packet or its enclosing structure (e.g. |ssh_request|).121 122In addition to the ``release`` callback, the |ssh_packet_ops| reference also123provides a ``complete()`` callback, which is run once the packet has been124completed and provides the status of this completion, i.e. zero on success125or a negative errno value in case of an error. Once the packet has been126submitted to the packet transport layer, the ``complete()`` callback is127always guaranteed to be executed before the ``release()`` callback, i.e. the128packet will always be completed, either successfully, with an error, or due129to cancellation, before it will be released.130 131The state of a packet is managed via its ``state`` flags132(|ssh_packet_flags|), which also contains the packet type. In particular,133the following bits are noteworthy:134 135* ``SSH_PACKET_SF_LOCKED_BIT``: This bit is set when completion, either136 through error or success, is imminent. It indicates that no further137 references of the packet should be taken and any existing references138 should be dropped as soon as possible. The process setting this bit is139 responsible for removing any references to this packet from the packet140 queue and pending set.141 142* ``SSH_PACKET_SF_COMPLETED_BIT``: This bit is set by the process running the143 ``complete()`` callback and is used to ensure that this callback only runs144 once.145 146* ``SSH_PACKET_SF_QUEUED_BIT``: This bit is set when the packet is queued on147 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 to150 the pending set and cleared when it is removed from it.151 152Packet Queue153------------154 155The packet queue is the first of the two fundamental collections in the156packet transport layer. It is a priority queue, with priority of the157respective packets based on the packet type (major) and number of tries158(minor). See |SSH_PACKET_PRIORITY| for more details on the priority value.159 160All packets to be transmitted by the transport layer must be submitted to161this queue via |ssh_ptl_submit|. Note that this includes control packets162sent by the transport layer itself. Internally, data packets can be163re-submitted to this queue due to timeouts or NAK packets sent by the EC.164 165Pending Set166-----------167 168The pending set is the second of the two fundamental collections in the169packet transport layer. It stores references to packets that have already170been transmitted, but wait for acknowledgment (e.g. the corresponding ACK171packet) by the EC.172 173Note that a packet may both be pending and queued if it has been174re-submitted due to a packet acknowledgment timeout or NAK. On such a175re-submission, packets are not removed from the pending set.176 177Transmitter Thread178------------------179 180The transmitter thread is responsible for most of the actual work regarding181packet transmission. In each iteration, it (waits for and) checks if the182next packet on the queue (if any) can be transmitted and, if so, removes it183from the queue and increments its counter for the number of transmission184attempts, i.e. tries. If the packet is sequenced, i.e. requires an ACK by185the EC, the packet is added to the pending set. Next, the packet's data is186submitted to the serdev subsystem. In case of an error or timeout during187this submission, the packet is completed by the transmitter thread with the188status value of the callback set accordingly. In case the packet is189unsequenced, i.e. does not require an ACK by the EC, the packet is completed190with success on the transmitter thread.191 192Transmission of sequenced packets is limited by the number of concurrently193pending packets, i.e. a limit on how many packets may be waiting for an ACK194from the EC in parallel. This limit is currently set to one (see195Documentation/driver-api/surface_aggregator/ssh.rst for the reasoning behind196this). Control packets (i.e. ACK and NAK) can always be transmitted.197 198Receiver Thread199---------------200 201Any data received from the EC is put into a FIFO buffer for further202processing. This processing happens on the receiver thread. The receiver203thread parses and validates the received message into its |ssh_frame| and204corresponding payload. It prepares and submits the necessary ACK (and on205validation error or invalid data NAK) packets for the received messages.206 207This thread also handles further processing, such as matching ACK messages208to the corresponding pending packet (via sequence ID) and completing it, as209well as initiating re-submission of all currently pending packets on210receival of a NAK message (re-submission in case of a NAK is similar to211re-submission due to timeout, see below for more details on that). Note that212the successful completion of a sequenced packet will always run on the213receiver thread (whereas any failure-indicating completion will run on the214process where the failure occurred).215 216Any payload data is forwarded via a callback to the next upper layer, i.e.217the request transport layer.218 219Timeout Reaper220--------------221 222The packet acknowledgment timeout is a per-packet timeout for sequenced223packets, started when the respective packet begins (re-)transmission (i.e.224this timeout is armed once per transmission attempt on the transmitter225thread). It is used to trigger re-submission or, when the number of tries226has been exceeded, cancellation of the packet in question.227 228This timeout is handled via a dedicated reaper task, which is essentially a229work item (re-)scheduled to run when the next packet is set to time out. The230work item then checks the set of pending packets for any packets that have231exceeded the timeout and, if there are any remaining packets, re-schedules232itself to the next appropriate point in time.233 234If a timeout has been detected by the reaper, the packet will either be235re-submitted if it still has some remaining tries left, or completed with236``-ETIMEDOUT`` as status if not. Note that re-submission, in this case and237triggered by receival of a NAK, means that the packet is added to the queue238with a now incremented number of tries, yielding a higher priority. The239timeout for the packet will be disabled until the next transmission attempt240and the packet remains on the pending set.241 242Note that due to transmission and packet acknowledgment timeouts, the packet243transport layer is always guaranteed to make progress, if only through244timing out packets, and will never fully block.245 246Concurrency and Locking247-----------------------248 249There are two main locks in the packet transport layer: One guarding access250to the packet queue and one guarding access to the pending set. These251collections may only be accessed and modified under the respective lock. If252access to both collections is needed, the pending lock must be acquired253before the queue lock to avoid deadlocks.254 255In addition to guarding the collections, after initial packet submission256certain packet fields may only be accessed under one of the locks.257Specifically, the packet priority must only be accessed while holding the258queue lock and the packet timestamp must only be accessed while holding the259pending lock.260 261Other parts of the packet transport layer are guarded independently. State262flags are managed by atomic bit operations and, if necessary, memory263barriers. Modifications to the timeout reaper work item and expiration date264are guarded by their own lock.265 266The reference of the packet to the packet transport layer (``ptl``) is267somewhat special. It is either set when the upper layer request is submitted268or, if there is none, when the packet is first submitted. After it is set,269it will not change its value. Functions that may run concurrently with270submission, i.e. cancellation, can not rely on the ``ptl`` reference to be271set. Access to it in these functions is guarded by ``READ_ONCE()``, whereas272setting ``ptl`` is equally guarded with ``WRITE_ONCE()`` for symmetry.273 274Some packet fields may be read outside of the respective locks guarding275them, specifically priority and state for tracing. In those cases, proper276access is ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``. Such277read-only access is only allowed when stale values are not critical.278 279With respect to the interface for higher layers, packet submission280(|ssh_ptl_submit|), packet cancellation (|ssh_ptl_cancel|), data receival281(|ssh_ptl_rx_rcvbuf|), and layer shutdown (|ssh_ptl_shutdown|) may always be282executed concurrently with respect to each other. Note that packet283submission may not run concurrently with itself for the same packet.284Equally, shutdown and data receival may also not run concurrently with285themselves (but may run concurrently with each other).286 287 288Request Transport Layer289=======================290 291The request transport layer is represented via |ssh_rtl| and builds on top292of the packet transport layer. It deals with requests, i.e. SSH packets sent293by the host containing a |ssh_command| as frame payload. This layer294separates responses to requests from events, which are also sent by the EC295via a |ssh_command| payload. While responses are handled in this layer,296events are relayed to the next upper layer, i.e. the controller layer, via297the corresponding callback. The request transport layer is structured around298the following key concepts:299 300Request301-------302 303Requests are packets with a command-type payload, sent from host to EC to304query data from or trigger an action on it (or both simultaneously). They305are represented by |ssh_request|, wrapping the underlying |ssh_packet|306storing its message data (i.e. SSH frame with command payload). Note that307all top-level representations, e.g. |ssam_request_sync| are built upon this308struct.309 310As |ssh_request| extends |ssh_packet|, its lifetime is also managed by the311reference counter inside the packet struct (which can be accessed via312|ssh_request_get| and |ssh_request_put|). Once the counter reaches zero, the313``release()`` callback of the |ssh_request_ops| reference of the request is314called.315 316Requests can have an optional response that is equally sent via a SSH317message with command-type payload (from EC to host). The party constructing318the request must know if a response is expected and mark this in the request319flags provided to |ssh_request_init|, so that the request transport layer320can wait for this response.321 322Similar to |ssh_packet|, |ssh_request| also has a ``complete()`` callback323provided via its request ops reference and is guaranteed to be completed324before it is released once it has been submitted to the request transport325layer via |ssh_rtl_submit|. For a request without a response, successful326completion will occur once the underlying packet has been successfully327transmitted by the packet transport layer (i.e. from within the packet328completion callback). For a request with response, successful completion329will occur once the response has been received and matched to the request330via its request ID (which happens on the packet layer's data-received331callback running on the receiver thread). If the request is completed with332an error, the status value will be set to the corresponding (negative) errno333value.334 335The state of a request is again managed via its ``state`` flags336(|ssh_request_flags|), which also encode the request type. In particular,337the following bits are noteworthy:338 339* ``SSH_REQUEST_SF_LOCKED_BIT``: This bit is set when completion, either340 through error or success, is imminent. It indicates that no further341 references of the request should be taken and any existing references342 should be dropped as soon as possible. The process setting this bit is343 responsible for removing any references to this request from the request344 queue and pending set.345 346* ``SSH_REQUEST_SF_COMPLETED_BIT``: This bit is set by the process running the347 ``complete()`` callback and is used to ensure that this callback only runs348 once.349 350* ``SSH_REQUEST_SF_QUEUED_BIT``: This bit is set when the request is queued on351 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 to354 the pending set and cleared when it is removed from it.355 356Request Queue357-------------358 359The request queue is the first of the two fundamental collections in the360request transport layer. In contrast to the packet queue of the packet361transport layer, it is not a priority queue and the simple first come first362serve principle applies.363 364All requests to be transmitted by the request transport layer must be365submitted to this queue via |ssh_rtl_submit|. Once submitted, requests may366not be re-submitted, and will not be re-submitted automatically on timeout.367Instead, the request is completed with a timeout error. If desired, the368caller can create and submit a new request for another try, but it must not369submit the same request again.370 371Pending Set372-----------373 374The pending set is the second of the two fundamental collections in the375request transport layer. This collection stores references to all pending376requests, i.e. requests awaiting a response from the EC (similar to what the377pending set of the packet transport layer does for packets).378 379Transmitter Task380----------------381 382The transmitter task is scheduled when a new request is available for383transmission. It checks if the next request on the request queue can be384transmitted and, if so, submits its underlying packet to the packet385transport layer. This check ensures that only a limited number of386requests can be pending, i.e. waiting for a response, at the same time. If387the request requires a response, the request is added to the pending set388before its packet is submitted.389 390Packet Completion Callback391--------------------------392 393The packet completion callback is executed once the underlying packet of a394request has been completed. In case of an error completion, the395corresponding request is completed with the error value provided in this396callback.397 398On successful packet completion, further processing depends on the request.399If the request expects a response, it is marked as transmitted and the400request timeout is started. If the request does not expect a response, it is401completed with success.402 403Data-Received Callback404----------------------405 406The data received callback notifies the request transport layer of data407being received by the underlying packet transport layer via a data-type408frame. In general, this is expected to be a command-type payload.409 410If the request ID of the command is one of the request IDs reserved for411events (one to ``SSH_NUM_EVENTS``, inclusively), it is forwarded to the412event callback registered in the request transport layer. If the request ID413indicates a response to a request, the respective request is looked up in414the pending set and, if found and marked as transmitted, completed with415success.416 417Timeout Reaper418--------------419 420The request-response-timeout is a per-request timeout for requests expecting421a response. It is used to ensure that a request does not wait indefinitely422on a response from the EC and is started after the underlying packet has423been successfully completed.424 425This timeout is, similar to the packet acknowledgment timeout on the packet426transport layer, handled via a dedicated reaper task. This task is427essentially a work-item (re-)scheduled to run when the next request is set428to time out. The work item then scans the set of pending requests for any429requests that have timed out and completes them with ``-ETIMEDOUT`` as430status. Requests will not be re-submitted automatically. Instead, the issuer431of the request must construct and submit a new request, if so desired.432 433Note that this timeout, in combination with packet transmission and434acknowledgment timeouts, guarantees that the request layer will always make435progress, even if only through timing out packets, and never fully block.436 437Concurrency and Locking438-----------------------439 440Similar to the packet transport layer, there are two main locks in the441request transport layer: One guarding access to the request queue and one442guarding access to the pending set. These collections may only be accessed443and modified under the respective lock.444 445Other parts of the request transport layer are guarded independently. State446flags are (again) managed by atomic bit operations and, if necessary, memory447barriers. Modifications to the timeout reaper work item and expiration date448are guarded by their own lock.449 450Some request fields may be read outside of the respective locks guarding451them, specifically the state for tracing. In those cases, proper access is452ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``. Such read-only453access is only allowed when stale values are not critical.454 455With respect to the interface for higher layers, request submission456(|ssh_rtl_submit|), request cancellation (|ssh_rtl_cancel|), and layer457shutdown (|ssh_rtl_shutdown|) may always be executed concurrently with458respect to each other. Note that request submission may not run concurrently459with itself for the same request (and also may only be called once per460request). Equally, shutdown may also not run concurrently with itself.461 462 463Controller Layer464================465 466The controller layer extends on the request transport layer to provide an467easy-to-use interface for client drivers. It is represented by468|ssam_controller| and the SSH driver. While the lower level transport layers469take care of transmitting and handling packets and requests, the controller470layer takes on more of a management role. Specifically, it handles device471initialization, power management, and event handling, including event472delivery and registration via the (event) completion system (|ssam_cplt|).473 474Event Registration475------------------476 477In general, an event (or rather a class of events) has to be explicitly478requested by the host before the EC will send it (HID input events seem to479be the exception). This is done via an event-enable request (similarly,480events should be disabled via an event-disable request once no longer481desired).482 483The specific request used to enable (or disable) an event is given via an484event registry, i.e. the governing authority of this event (so to speak),485represented by |ssam_event_registry|. As parameters to this request, the486target category and, depending on the event registry, instance ID of the487event to be enabled must be provided. This (optional) instance ID must be488zero if the registry does not use it. Together, target category and instance489ID form the event ID, represented by |ssam_event_id|. In short, both, event490registry and event ID, are required to uniquely identify a respective class491of events.492 493Note that a further *request ID* parameter must be provided for the494enable-event request. This parameter does not influence the class of events495being enabled, but instead is set as the request ID (RQID) on each event of496this class sent by the EC. It is used to identify events (as a limited497number of request IDs is reserved for use in events only, specifically one498to ``SSH_NUM_EVENTS`` inclusively) and also map events to their specific499class. Currently, the controller always sets this parameter to the target500category specified in |ssam_event_id|.501 502As multiple client drivers may rely on the same (or overlapping) classes of503events and enable/disable calls are strictly binary (i.e. on/off), the504controller has to manage access to these events. It does so via reference505counting, storing the counter inside an RB-tree based mapping with event506registry and ID as key (there is no known list of valid event registry and507event ID combinations). See |ssam_nf|, |ssam_nf_refcount_inc|, and508|ssam_nf_refcount_dec| for details.509 510This management is done together with notifier registration (described in511the next section) via the top-level |ssam_notifier_register| and512|ssam_notifier_unregister| functions.513 514Event Delivery515--------------516 517To receive events, a client driver has to register an event notifier via518|ssam_notifier_register|. This increments the reference counter for that519specific class of events (as detailed in the previous section), enables the520class on the EC (if it has not been enabled already), and installs the521provided notifier callback.522 523Notifier callbacks are stored in lists, with one (RCU) list per target524category (provided via the event ID; NB: there is a fixed known number of525target categories). There is no known association from the combination of526event registry and event ID to the command data (target ID, target category,527command ID, and instance ID) that can be provided by an event class, apart528from target category and instance ID given via the event ID.529 530Note that due to the way notifiers are (or rather have to be) stored, client531drivers may receive events that they have not requested and need to account532for them. Specifically, they will, by default, receive all events from the533same target category. To simplify dealing with this, filtering of events by534target ID (provided via the event registry) and instance ID (provided via535the event ID) can be requested when registering a notifier. This filtering536is applied when iterating over the notifiers at the time they are executed.537 538All notifier callbacks are executed on a dedicated workqueue, the so-called539completion workqueue. After an event has been received via the callback540installed in the request layer (running on the receiver thread of the packet541transport layer), it will be put on its respective event queue542(|ssam_event_queue|). From this event queue the completion work item of that543queue (running on the completion workqueue) will pick up the event and544execute the notifier callback. This is done to avoid blocking on the545receiver thread.546 547There is one event queue per combination of target ID and target category.548This is done to ensure that notifier callbacks are executed in sequence for549events of the same target ID and target category. Callbacks can be executed550in parallel for events with a different combination of target ID and target551category.552 553Concurrency and Locking554-----------------------555 556Most of the concurrency related safety guarantees of the controller are557provided by the lower-level request transport layer. In addition to this,558event (un-)registration is guarded by its own lock.559 560Access to the controller state is guarded by the state lock. This lock is a561read/write semaphore. The reader part can be used to ensure that the state562does not change while functions depending on the state to stay the same563(e.g. |ssam_notifier_register|, |ssam_notifier_unregister|,564|ssam_request_sync_submit|, and derivatives) are executed and this guarantee565is not already provided otherwise (e.g. through |ssam_client_bind| or566|ssam_client_link|). The writer part guards any transitions that will change567the state, i.e. initialization, destruction, suspension, and resumption.568 569The controller state may be accessed (read-only) outside the state lock for570smoke-testing against invalid API usage (e.g. in |ssam_request_sync_submit|).571Note that such checks are not supposed to (and will not) protect against all572invalid usages, but rather aim to help catch them. In those cases, proper573variable access is ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``.574 575Assuming any preconditions on the state not changing have been satisfied,576all non-initialization and non-shutdown functions may run concurrently with577each 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