cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

internal.rst (29571B)


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