linux/drivers/firmware/arm_scmi/raw_mode.c

// SPDX-License-Identifier: GPL-2.0
/*
 * System Control and Management Interface (SCMI) Raw mode support
 *
 * Copyright (C) 2022 ARM Ltd.
 */
/**
 * DOC: Theory of operation
 *
 * When enabled the SCMI Raw mode support exposes a userspace API which allows
 * to send and receive SCMI commands, replies and notifications from a user
 * application through injection and snooping of bare SCMI messages in binary
 * little-endian format.
 *
 * Such injected SCMI transactions will then be routed through the SCMI core
 * stack towards the SCMI backend server using whatever SCMI transport is
 * currently configured on the system under test.
 *
 * It is meant to help in running any sort of SCMI backend server testing, no
 * matter where the server is placed, as long as it is normally reachable via
 * the transport configured on the system.
 *
 * It is activated by a Kernel configuration option since it is NOT meant to
 * be used in production but only during development and in CI deployments.
 *
 * In order to avoid possible interferences between the SCMI Raw transactions
 * originated from a test-suite and the normal operations of the SCMI drivers,
 * when Raw mode is enabled, by default, all the regular SCMI drivers are
 * inhibited, unless CONFIG_ARM_SCMI_RAW_MODE_SUPPORT_COEX is enabled: in this
 * latter case the regular SCMI stack drivers will be loaded as usual and it is
 * up to the user of this interface to take care of manually inhibiting the
 * regular SCMI drivers in order to avoid interferences during the test runs.
 *
 * The exposed API is as follows.
 *
 * All SCMI Raw entries are rooted under a common top /raw debugfs top directory
 * which in turn is rooted under the corresponding underlying  SCMI instance.
 *
 * /sys/kernel/debug/scmi/
 * `-- 0
 *     |-- atomic_threshold_us
 *     |-- instance_name
 *     |-- raw
 *     |   |-- channels
 *     |   |   |-- 0x10
 *     |   |   |   |-- message
 *     |   |   |   `-- message_async
 *     |   |   `-- 0x13
 *     |   |       |-- message
 *     |   |       `-- message_async
 *     |   |-- errors
 *     |   |-- message
 *     |   |-- message_async
 *     |   |-- notification
 *     |   `-- reset
 *     `-- transport
 *         |-- is_atomic
 *         |-- max_msg_size
 *         |-- max_rx_timeout_ms
 *         |-- rx_max_msg
 *         |-- tx_max_msg
 *         `-- type
 *
 * where:
 *
 *  - errors: used to read back timed-out and unexpected replies
 *  - message*: used to send sync/async commands and read back immediate and
 *		delayed reponses (if any)
 *  - notification: used to read any notification being emitted by the system
 *		    (if previously enabled by the user app)
 *  - reset: used to flush the queues of messages (of any kind) still pending
 *	     to be read; this is useful at test-suite start/stop to get
 *	     rid of any unread messages from the previous run.
 *
 * with the per-channel entries rooted at /channels being present only on a
 * system where multiple transport channels have been configured.
 *
 * Such per-channel entries can be used to explicitly choose a specific channel
 * for SCMI bare message injection, in contrast with the general entries above
 * where, instead, the selection of the proper channel to use is automatically
 * performed based the protocol embedded in the injected message and on how the
 * transport is configured on the system.
 *
 * Note that other common general entries are available under transport/ to let
 * the user applications properly make up their expectations in terms of
 * timeouts and message characteristics.
 *
 * Each write to the message* entries causes one command request to be built
 * and sent while the replies or delayed response are read back from those same
 * entries one message at time (receiving an EOF at each message boundary).
 *
 * The user application running the test is in charge of handling timeouts
 * on replies and properly choosing SCMI sequence numbers for the outgoing
 * requests (using the same sequence number is supported but discouraged).
 *
 * Injection of multiple in-flight requests is supported as long as the user
 * application uses properly distinct sequence numbers for concurrent requests
 * and takes care to properly manage all the related issues about concurrency
 * and command/reply pairing. Keep in mind that, anyway, the real level of
 * parallelism attainable in such scenario is dependent on the characteristics
 * of the underlying transport being used.
 *
 * Since the SCMI core regular stack is partially used to deliver and collect
 * the messages, late replies arrived after timeouts and any other sort of
 * unexpected message can be identified by the SCMI core as usual and they will
 * be reported as messages under "errors" for later analysis.
 */

#include <linux/bitmap.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/xarray.h>

#include "common.h"

#include "raw_mode.h"

#include <trace/events/scmi.h>

#define SCMI_XFER_RAW_MAX_RETRIES

/**
 * struct scmi_raw_queue  - Generic Raw queue descriptor
 *
 * @free_bufs: A freelists listhead used to keep unused raw buffers
 * @free_bufs_lock: Spinlock used to protect access to @free_bufs
 * @msg_q: A listhead to a queue of snooped messages waiting to be read out
 * @msg_q_lock: Spinlock used to protect access to @msg_q
 * @wq: A waitqueue used to wait and poll on related @msg_q
 */
struct scmi_raw_queue {};

/**
 * struct scmi_raw_mode_info  - Structure holding SCMI Raw instance data
 *
 * @id: Sequential Raw instance ID.
 * @handle: Pointer to SCMI entity handle to use
 * @desc: Pointer to the transport descriptor to use
 * @tx_max_msg: Maximum number of concurrent TX in-flight messages
 * @q: An array of Raw queue descriptors
 * @chans_q: An XArray mapping optional additional per-channel queues
 * @free_waiters: Head of freelist for unused waiters
 * @free_mtx: A mutex to protect the waiters freelist
 * @active_waiters: Head of list for currently active and used waiters
 * @active_mtx: A mutex to protect the active waiters list
 * @waiters_work: A work descriptor to be used with the workqueue machinery
 * @wait_wq: A workqueue reference to the created workqueue
 * @dentry: Top debugfs root dentry for SCMI Raw
 * @gid: A group ID used for devres accounting
 *
 * Note that this descriptor is passed back to the core after SCMI Raw is
 * initialized as an opaque handle to use by subsequent SCMI Raw call hooks.
 *
 */
struct scmi_raw_mode_info {};

/**
 * struct scmi_xfer_raw_waiter  - Structure to describe an xfer to be waited for
 *
 * @start_jiffies: The timestamp in jiffies of when this structure was queued.
 * @cinfo: A reference to the channel to use for this transaction
 * @xfer: A reference to the xfer to be waited for
 * @async_response: A completion to be, optionally, used for async waits: it
 *		    will be setup by @scmi_do_xfer_raw_start, if needed, to be
 *		    pointed at by xfer->async_done.
 * @node: A list node.
 */
struct scmi_xfer_raw_waiter {};

/**
 * struct scmi_raw_buffer  - Structure to hold a full SCMI message
 *
 * @max_len: The maximum allowed message size (header included) that can be
 *	     stored into @msg
 * @msg: A message buffer used to collect a full message grabbed from an xfer.
 * @node: A list node.
 */
struct scmi_raw_buffer {};

/**
 * struct scmi_dbg_raw_data  - Structure holding data needed by the debugfs
 * layer
 *
 * @chan_id: The preferred channel to use: if zero the channel is automatically
 *	     selected based on protocol.
 * @raw: A reference to the Raw instance.
 * @tx: A message buffer used to collect TX message on write.
 * @tx_size: The effective size of the TX message.
 * @tx_req_size: The final expected size of the complete TX message.
 * @rx: A message buffer to collect RX message on read.
 * @rx_size: The effective size of the RX message.
 */
struct scmi_dbg_raw_data {};

static struct scmi_raw_queue *
scmi_raw_queue_select(struct scmi_raw_mode_info *raw, unsigned int idx,
		      unsigned int chan_id)
{}

static struct scmi_raw_buffer *scmi_raw_buffer_get(struct scmi_raw_queue *q)
{}

static void scmi_raw_buffer_put(struct scmi_raw_queue *q,
				struct scmi_raw_buffer *rb)
{}

static void scmi_raw_buffer_enqueue(struct scmi_raw_queue *q,
				    struct scmi_raw_buffer *rb)
{}

static struct scmi_raw_buffer*
scmi_raw_buffer_dequeue_unlocked(struct scmi_raw_queue *q)
{}

static struct scmi_raw_buffer *scmi_raw_buffer_dequeue(struct scmi_raw_queue *q)
{}

static void scmi_raw_buffer_queue_flush(struct scmi_raw_queue *q)
{}

static struct scmi_xfer_raw_waiter *
scmi_xfer_raw_waiter_get(struct scmi_raw_mode_info *raw, struct scmi_xfer *xfer,
			 struct scmi_chan_info *cinfo, bool async)
{}

static void scmi_xfer_raw_waiter_put(struct scmi_raw_mode_info *raw,
				     struct scmi_xfer_raw_waiter *rw)
{}

static void scmi_xfer_raw_waiter_enqueue(struct scmi_raw_mode_info *raw,
					 struct scmi_xfer_raw_waiter *rw)
{}

static struct scmi_xfer_raw_waiter *
scmi_xfer_raw_waiter_dequeue(struct scmi_raw_mode_info *raw)
{}

/**
 * scmi_xfer_raw_worker  - Work function to wait for Raw xfers completions
 *
 * @work: A reference to the work.
 *
 * In SCMI Raw mode, once a user-provided injected SCMI message is sent, we
 * cannot wait to receive its response (if any) in the context of the injection
 * routines so as not to leave the userspace write syscall, which delivered the
 * SCMI message to send, pending till eventually a reply is received.
 * Userspace should and will poll/wait instead on the read syscalls which will
 * be in charge of reading a received reply (if any).
 *
 * Even though reply messages are collected and reported into the SCMI Raw layer
 * on the RX path, nonetheless we have to properly wait for their completion as
 * usual (and async_completion too if needed) in order to properly release the
 * xfer structure at the end: to do this out of the context of the write/send
 * these waiting jobs are delegated to this deferred worker.
 *
 * Any sent xfer, to be waited for, is timestamped and queued for later
 * consumption by this worker: queue aging is accounted for while choosing a
 * timeout for the completion, BUT we do not really care here if we end up
 * accidentally waiting for a bit too long.
 */
static void scmi_xfer_raw_worker(struct work_struct *work)
{}

static void scmi_xfer_raw_reset(struct scmi_raw_mode_info *raw)
{}

/**
 * scmi_xfer_raw_get_init  - An helper to build a valid xfer from the provided
 * bare SCMI message.
 *
 * @raw: A reference to the Raw instance.
 * @buf: A buffer containing the whole SCMI message to send (including the
 *	 header) in little-endian binary formmat.
 * @len: Length of the message in @buf.
 * @p: A pointer to return the initialized Raw xfer.
 *
 * After an xfer is picked from the TX pool and filled in with the message
 * content, the xfer is registered as pending with the core in the usual way
 * using the original sequence number provided by the user with the message.
 *
 * Note that, in case the testing user application is NOT using distinct
 * sequence-numbers between successive SCMI messages such registration could
 * fail temporarily if the previous message, using the same sequence number,
 * had still not released; in such a case we just wait and retry.
 *
 * Return: 0 on Success
 */
static int scmi_xfer_raw_get_init(struct scmi_raw_mode_info *raw, void *buf,
				  size_t len, struct scmi_xfer **p)
{}

/**
 * scmi_do_xfer_raw_start  - An helper to send a valid raw xfer
 *
 * @raw: A reference to the Raw instance.
 * @xfer: The xfer to send
 * @chan_id: The channel ID to use, if zero the channels is automatically
 *	     selected based on the protocol used.
 * @async: A flag stating if an asynchronous command is required.
 *
 * This function send a previously built raw xfer using an appropriate channel
 * and queues the related waiting work.
 *
 * Note that we need to know explicitly if the required command is meant to be
 * asynchronous in kind since we have to properly setup the waiter.
 * (and deducing this from the payload is weak and do not scale given there is
 *  NOT a common header-flag stating if the command is asynchronous or not)
 *
 * Return: 0 on Success
 */
static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw,
				  struct scmi_xfer *xfer, u8 chan_id,
				  bool async)
{}

/**
 * scmi_raw_message_send  - An helper to build and send an SCMI command using
 * the provided SCMI bare message buffer
 *
 * @raw: A reference to the Raw instance.
 * @buf: A buffer containing the whole SCMI message to send (including the
 *	 header) in little-endian binary format.
 * @len: Length of the message in @buf.
 * @chan_id: The channel ID to use.
 * @async: A flag stating if an asynchronous command is required.
 *
 * Return: 0 on Success
 */
static int scmi_raw_message_send(struct scmi_raw_mode_info *raw,
				 void *buf, size_t len, u8 chan_id, bool async)
{}

static struct scmi_raw_buffer *
scmi_raw_message_dequeue(struct scmi_raw_queue *q, bool o_nonblock)
{}

/**
 * scmi_raw_message_receive  - An helper to dequeue and report the next
 * available enqueued raw message payload that has been collected.
 *
 * @raw: A reference to the Raw instance.
 * @buf: A buffer to get hold of the whole SCMI message received and represented
 *	 in little-endian binary format.
 * @len: Length of @buf.
 * @size: The effective size of the message copied into @buf
 * @idx: The index of the queue to pick the next queued message from.
 * @chan_id: The channel ID to use.
 * @o_nonblock: A flag to request a non-blocking message dequeue.
 *
 * Return: 0 on Success
 */
static int scmi_raw_message_receive(struct scmi_raw_mode_info *raw,
				    void *buf, size_t len, size_t *size,
				    unsigned int idx, unsigned int chan_id,
				    bool o_nonblock)
{}

/* SCMI Raw debugfs helpers */

static ssize_t scmi_dbg_raw_mode_common_read(struct file *filp,
					     char __user *buf,
					     size_t count, loff_t *ppos,
					     unsigned int idx)
{}

static ssize_t scmi_dbg_raw_mode_common_write(struct file *filp,
					      const char __user *buf,
					      size_t count, loff_t *ppos,
					      bool async)
{}

static __poll_t scmi_test_dbg_raw_common_poll(struct file *filp,
					      struct poll_table_struct *wait,
					      unsigned int idx)
{}

static ssize_t scmi_dbg_raw_mode_message_read(struct file *filp,
					      char __user *buf,
					      size_t count, loff_t *ppos)
{}

static ssize_t scmi_dbg_raw_mode_message_write(struct file *filp,
					       const char __user *buf,
					       size_t count, loff_t *ppos)
{}

static __poll_t scmi_dbg_raw_mode_message_poll(struct file *filp,
					       struct poll_table_struct *wait)
{}

static int scmi_dbg_raw_mode_open(struct inode *inode, struct file *filp)
{}

static int scmi_dbg_raw_mode_release(struct inode *inode, struct file *filp)
{}

static ssize_t scmi_dbg_raw_mode_reset_write(struct file *filp,
					     const char __user *buf,
					     size_t count, loff_t *ppos)
{}

static const struct file_operations scmi_dbg_raw_mode_reset_fops =;

static const struct file_operations scmi_dbg_raw_mode_message_fops =;

static ssize_t scmi_dbg_raw_mode_message_async_write(struct file *filp,
						     const char __user *buf,
						     size_t count, loff_t *ppos)
{}

static const struct file_operations scmi_dbg_raw_mode_message_async_fops =;

static ssize_t scmi_test_dbg_raw_mode_notif_read(struct file *filp,
						 char __user *buf,
						 size_t count, loff_t *ppos)
{}

static __poll_t
scmi_test_dbg_raw_mode_notif_poll(struct file *filp,
				  struct poll_table_struct *wait)
{}

static const struct file_operations scmi_dbg_raw_mode_notification_fops =;

static ssize_t scmi_test_dbg_raw_mode_errors_read(struct file *filp,
						  char __user *buf,
						  size_t count, loff_t *ppos)
{}

static __poll_t
scmi_test_dbg_raw_mode_errors_poll(struct file *filp,
				   struct poll_table_struct *wait)
{}

static const struct file_operations scmi_dbg_raw_mode_errors_fops =;

static struct scmi_raw_queue *
scmi_raw_queue_init(struct scmi_raw_mode_info *raw)
{}

static int scmi_xfer_raw_worker_init(struct scmi_raw_mode_info *raw)
{}

static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
			       u8 *channels, int num_chans)
{}

/**
 * scmi_raw_mode_init  - Function to initialize the SCMI Raw stack
 *
 * @handle: Pointer to SCMI entity handle
 * @top_dentry: A reference to the top Raw debugfs dentry
 * @instance_id: The ID of the underlying SCMI platform instance represented by
 *		 this Raw instance
 * @channels: The list of the existing channels
 * @num_chans: The number of entries in @channels
 * @desc: Reference to the transport operations
 * @tx_max_msg: Max number of in-flight messages allowed by the transport
 *
 * This function prepare the SCMI Raw stack and creates the debugfs API.
 *
 * Return: An opaque handle to the Raw instance on Success, an ERR_PTR otherwise
 */
void *scmi_raw_mode_init(const struct scmi_handle *handle,
			 struct dentry *top_dentry, int instance_id,
			 u8 *channels, int num_chans,
			 const struct scmi_desc *desc, int tx_max_msg)
{}

/**
 * scmi_raw_mode_cleanup  - Function to cleanup the SCMI Raw stack
 *
 * @r: An opaque handle to an initialized SCMI Raw instance
 */
void scmi_raw_mode_cleanup(void *r)
{}

static int scmi_xfer_raw_collect(void *msg, size_t *msg_len,
				 struct scmi_xfer *xfer)
{}

/**
 * scmi_raw_message_report  - Helper to report back valid reponses/notifications
 * to raw message requests.
 *
 * @r: An opaque reference to the raw instance configuration
 * @xfer: The xfer containing the message to be reported
 * @idx: The index of the queue.
 * @chan_id: The channel ID to use.
 *
 * If Raw mode is enabled, this is called from the SCMI core on the regular RX
 * path to save and enqueue the response/notification payload carried by this
 * xfer into a dedicated scmi_raw_buffer for later consumption by the user.
 *
 * This way the caller can free the related xfer immediately afterwards and the
 * user can read back the raw message payload at its own pace (if ever) without
 * holding an xfer for too long.
 */
void scmi_raw_message_report(void *r, struct scmi_xfer *xfer,
			     unsigned int idx, unsigned int chan_id)
{}

static void scmi_xfer_raw_fill(struct scmi_raw_mode_info *raw,
			       struct scmi_chan_info *cinfo,
			       struct scmi_xfer *xfer, u32 msg_hdr)
{}

/**
 * scmi_raw_error_report  - Helper to report back timed-out or generally
 * unexpected replies.
 *
 * @r: An opaque reference to the raw instance configuration
 * @cinfo: A reference to the channel to use to retrieve the broken xfer
 * @msg_hdr: The SCMI message header of the message to fetch and report
 * @priv: Any private data related to the xfer.
 *
 * If Raw mode is enabled, this is called from the SCMI core on the RX path in
 * case of errors to save and enqueue the bad message payload carried by the
 * message that has just been received.
 *
 * Note that we have to manually fetch any available payload into a temporary
 * xfer to be able to save and enqueue the message, since the regular RX error
 * path which had called this would have not fetched the message payload having
 * classified it as an error.
 */
void scmi_raw_error_report(void *r, struct scmi_chan_info *cinfo,
			   u32 msg_hdr, void *priv)
{}