summaryrefslogtreecommitdiff
path: root/drivers/firmware/arm_scmi/common.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/arm_scmi/common.h')
-rw-r--r--drivers/firmware/arm_scmi/common.h254
1 files changed, 209 insertions, 45 deletions
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 6affbfdd1dec..dab758c5fdea 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -4,7 +4,7 @@
* driver common header file containing some definitions, structures
* and function prototypes used in all the different SCMI protocols.
*
- * Copyright (C) 2018-2022 ARM Ltd.
+ * Copyright (C) 2018-2024 ARM Ltd.
*/
#ifndef _SCMI_COMMON_H
#define _SCMI_COMMON_H
@@ -22,7 +22,7 @@
#include <linux/spinlock.h>
#include <linux/types.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "protocols.h"
#include "notify.h"
@@ -31,6 +31,8 @@
#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC)
+#define SCMI_SHMEM_MAX_PAYLOAD_SIZE 104
+
enum scmi_error_codes {
SCMI_SUCCESS = 0, /* Success */
SCMI_ERR_SUPPORT = -1, /* Not supported */
@@ -163,7 +165,9 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
* used to initialize this channel
* @dev: Reference to device in the SCMI hierarchy corresponding to this
* channel
+ * @is_p2a: A flag to identify a channel as P2A (RX)
* @rx_timeout_ms: The configured RX timeout in milliseconds.
+ * @max_msg_size: Maximum size of message payload.
* @handle: Pointer to SCMI entity handle
* @no_completion_irq: Flag to indicate that this channel has no completion
* interrupt mechanism for synchronous commands.
@@ -174,7 +178,9 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
struct scmi_chan_info {
int id;
struct device *dev;
+ bool is_p2a;
unsigned int rx_timeout_ms;
+ unsigned int max_msg_size;
struct scmi_handle *handle;
bool no_completion_irq;
void *transport_info;
@@ -183,7 +189,6 @@ struct scmi_chan_info {
/**
* struct scmi_transport_ops - Structure representing a SCMI transport ops
*
- * @link_supplier: Optional callback to add link to a supplier device
* @chan_available: Callback to check if channel is available or not
* @chan_setup: Callback to allocate and setup a channel
* @chan_free: Callback to free a channel
@@ -198,7 +203,6 @@ struct scmi_chan_info {
* @poll_done: Callback to poll transfer status
*/
struct scmi_transport_ops {
- int (*link_supplier)(struct device *dev);
bool (*chan_available)(struct device_node *of_node, int idx);
int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev,
bool tx);
@@ -219,18 +223,18 @@ struct scmi_transport_ops {
/**
* struct scmi_desc - Description of SoC integration
*
- * @transport_init: An optional function that a transport can provide to
- * initialize some transport-specific setup during SCMI core
- * initialization, so ahead of SCMI core probing.
- * @transport_exit: An optional function that a transport can provide to
- * de-initialize some transport-specific setup during SCMI core
- * de-initialization, so after SCMI core removal.
* @ops: Pointer to the transport specific ops structure
* @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
* @max_msg: Maximum number of messages for a channel type (tx or rx) that can
* be pending simultaneously in the system. May be overridden by the
* get_max_msg op.
- * @max_msg_size: Maximum size of data per message that can be handled.
+ * @max_msg_size: Maximum size of data payload per message that can be handled.
+ * @atomic_threshold: Optional system wide DT-configured threshold, expressed
+ * in microseconds, for atomic operations.
+ * Only SCMI synchronous commands reported by the platform
+ * to have an execution latency lesser-equal to the threshold
+ * should be considered for atomic mode operation: such
+ * decision is finally left up to the SCMI drivers.
* @force_polling: Flag to force this whole transport to use SCMI core polling
* mechanism instead of completion interrupts even if available.
* @sync_cmds_completed_on_ret: Flag to indicate that the transport assures
@@ -245,12 +249,11 @@ struct scmi_transport_ops {
* when requested.
*/
struct scmi_desc {
- int (*transport_init)(void);
- void (*transport_exit)(void);
const struct scmi_transport_ops *ops;
int max_rx_timeout_ms;
int max_msg;
int max_msg_size;
+ unsigned int atomic_threshold;
const bool force_polling;
const bool sync_cmds_completed_on_ret;
const bool atomic_enabled;
@@ -286,35 +289,101 @@ int scmi_xfer_raw_inflight_register(const struct scmi_handle *handle,
int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo,
struct scmi_xfer *xfer,
unsigned int timeout_ms);
-#ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX
-extern const struct scmi_desc scmi_mailbox_desc;
-#endif
-#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
-extern const struct scmi_desc scmi_smc_desc;
-#endif
-#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
-extern const struct scmi_desc scmi_virtio_desc;
-#endif
-#ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE
-extern const struct scmi_desc scmi_optee_desc;
-#endif
-
-void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv);
+
+enum debug_counters {
+ SENT_OK,
+ SENT_FAIL,
+ SENT_FAIL_POLLING_UNSUPPORTED,
+ SENT_FAIL_CHANNEL_NOT_FOUND,
+ RESPONSE_OK,
+ NOTIFICATION_OK,
+ DELAYED_RESPONSE_OK,
+ XFERS_RESPONSE_TIMEOUT,
+ XFERS_RESPONSE_POLLED_TIMEOUT,
+ RESPONSE_POLLED_OK,
+ ERR_MSG_UNEXPECTED,
+ ERR_MSG_INVALID,
+ ERR_MSG_NOMEM,
+ ERR_PROTOCOL,
+ SCMI_DEBUG_COUNTERS_LAST
+};
+
+static inline void scmi_inc_count(atomic_t *arr, int stat)
+{
+ if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS))
+ atomic_inc(&arr[stat]);
+}
+
+enum scmi_bad_msg {
+ MSG_UNEXPECTED = -1,
+ MSG_INVALID = -2,
+ MSG_UNKNOWN = -3,
+ MSG_NOMEM = -4,
+ MSG_MBOX_SPURIOUS = -5,
+};
+
+/* Used for compactness and signature validation of the function pointers being
+ * passed.
+ */
+typedef void (*shmem_copy_toio_t)(void __iomem *to, const void *from,
+ size_t count);
+typedef void (*shmem_copy_fromio_t)(void *to, const void __iomem *from,
+ size_t count);
+
+/**
+ * struct scmi_shmem_io_ops - I/O operations to read from/write to
+ * Shared Memory
+ *
+ * @toio: Copy data to the shared memory area
+ * @fromio: Copy data from the shared memory area
+ */
+struct scmi_shmem_io_ops {
+ shmem_copy_fromio_t fromio;
+ shmem_copy_toio_t toio;
+};
/* shmem related declarations */
struct scmi_shared_mem;
-void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
- struct scmi_xfer *xfer, struct scmi_chan_info *cinfo);
-u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem);
-void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
+/**
+ * struct scmi_shared_mem_operations - Transport core operations for
+ * Shared Memory
+ *
+ * @tx_prepare: Prepare the @xfer message for transmission on the chosen @shmem
+ * @read_header: Read header of the message currently hold in @shmem
+ * @fetch_response: Copy the message response from @shmem into @xfer
+ * @fetch_notification: Copy the message notification from @shmem into @xfer
+ * @clear_channel: Clear the @shmem channel busy flag
+ * @poll_done: Check if poll has completed for @xfer on @shmem
+ * @channel_free: Check if @shmem channel is marked as free
+ * @channel_intr_enabled: Check is @shmem channel has requested a completion irq
+ * @setup_iomap: Setup IO shared memory for channel @cinfo
+ */
+struct scmi_shared_mem_operations {
+ void (*tx_prepare)(struct scmi_shared_mem __iomem *shmem,
+ struct scmi_xfer *xfer,
+ struct scmi_chan_info *cinfo,
+ shmem_copy_toio_t toio);
+ u32 (*read_header)(struct scmi_shared_mem __iomem *shmem);
+
+ void (*fetch_response)(struct scmi_shared_mem __iomem *shmem,
+ struct scmi_xfer *xfer,
+ shmem_copy_fromio_t fromio);
+ void (*fetch_notification)(struct scmi_shared_mem __iomem *shmem,
+ size_t max_len, struct scmi_xfer *xfer,
+ shmem_copy_fromio_t fromio);
+ void (*clear_channel)(struct scmi_shared_mem __iomem *shmem);
+ bool (*poll_done)(struct scmi_shared_mem __iomem *shmem,
struct scmi_xfer *xfer);
-void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
- size_t max_len, struct scmi_xfer *xfer);
-void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
-bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
- struct scmi_xfer *xfer);
-bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem);
+ bool (*channel_free)(struct scmi_shared_mem __iomem *shmem);
+ bool (*channel_intr_enabled)(struct scmi_shared_mem __iomem *shmem);
+ void __iomem *(*setup_iomap)(struct scmi_chan_info *cinfo,
+ struct device *dev,
+ bool tx, struct resource *res,
+ struct scmi_shmem_io_ops **ops);
+};
+
+const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void);
/* declarations for message passing transports */
struct scmi_msg_payld;
@@ -322,14 +391,109 @@ struct scmi_msg_payld;
/* Maximum overhead of message w.r.t. struct scmi_desc.max_msg_size */
#define SCMI_MSG_MAX_PROT_OVERHEAD (2 * sizeof(__le32))
-size_t msg_response_size(struct scmi_xfer *xfer);
-size_t msg_command_size(struct scmi_xfer *xfer);
-void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer);
-u32 msg_read_header(struct scmi_msg_payld *msg);
-void msg_fetch_response(struct scmi_msg_payld *msg, size_t len,
- struct scmi_xfer *xfer);
-void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len,
- size_t max_len, struct scmi_xfer *xfer);
+/**
+ * struct scmi_message_operations - Transport core operations for Message
+ *
+ * @response_size: Get calculated response size for @xfer
+ * @command_size: Get calculated command size for @xfer
+ * @tx_prepare: Prepare the @xfer message for transmission on the provided @msg
+ * @read_header: Read header of the message currently hold in @msg
+ * @fetch_response: Copy the message response from @msg into @xfer
+ * @fetch_notification: Copy the message notification from @msg into @xfer
+ */
+struct scmi_message_operations {
+ size_t (*response_size)(struct scmi_xfer *xfer);
+ size_t (*command_size)(struct scmi_xfer *xfer);
+ void (*tx_prepare)(struct scmi_msg_payld *msg, struct scmi_xfer *xfer);
+ u32 (*read_header)(struct scmi_msg_payld *msg);
+ void (*fetch_response)(struct scmi_msg_payld *msg, size_t len,
+ struct scmi_xfer *xfer);
+ void (*fetch_notification)(struct scmi_msg_payld *msg, size_t len,
+ size_t max_len, struct scmi_xfer *xfer);
+};
+
+const struct scmi_message_operations *scmi_message_operations_get(void);
+
+/**
+ * struct scmi_transport_core_operations - Transpoert core operations
+ *
+ * @bad_message_trace: An helper to report a malformed/unexpected message
+ * @rx_callback: Callback to report received messages
+ * @shmem: Datagram operations for shared memory based transports
+ * @msg: Datagram operations for message based transports
+ */
+struct scmi_transport_core_operations {
+ void (*bad_message_trace)(struct scmi_chan_info *cinfo,
+ u32 msg_hdr, enum scmi_bad_msg err);
+ void (*rx_callback)(struct scmi_chan_info *cinfo, u32 msg_hdr,
+ void *priv);
+ const struct scmi_shared_mem_operations *shmem;
+ const struct scmi_message_operations *msg;
+};
+
+/**
+ * struct scmi_transport - A structure representing a configured transport
+ *
+ * @supplier: Device representing the transport and acting as a supplier for
+ * the core SCMI stack
+ * @desc: Transport descriptor
+ * @core_ops: A pointer to a pointer used by the core SCMI stack to make the
+ * core transport operations accessible to the transports.
+ */
+struct scmi_transport {
+ struct device *supplier;
+ struct scmi_desc desc;
+ struct scmi_transport_core_operations **core_ops;
+};
+
+#define DEFINE_SCMI_TRANSPORT_DRIVER(__tag, __drv, __desc, __match, __core_ops)\
+static void __tag##_dev_free(void *data) \
+{ \
+ struct platform_device *spdev = data; \
+ \
+ platform_device_unregister(spdev); \
+} \
+ \
+static int __tag##_probe(struct platform_device *pdev) \
+{ \
+ struct device *dev = &pdev->dev; \
+ struct platform_device *spdev; \
+ struct scmi_transport strans; \
+ int ret; \
+ \
+ spdev = platform_device_alloc("arm-scmi", PLATFORM_DEVID_AUTO); \
+ if (!spdev) \
+ return -ENOMEM; \
+ \
+ device_set_of_node_from_dev(&spdev->dev, dev); \
+ \
+ strans.supplier = dev; \
+ memcpy(&strans.desc, &(__desc), sizeof(strans.desc)); \
+ strans.core_ops = &(__core_ops); \
+ \
+ ret = platform_device_add_data(spdev, &strans, sizeof(strans)); \
+ if (ret) \
+ goto err; \
+ \
+ spdev->dev.parent = dev; \
+ ret = platform_device_add(spdev); \
+ if (ret) \
+ goto err; \
+ \
+ return devm_add_action_or_reset(dev, __tag##_dev_free, spdev); \
+ \
+err: \
+ platform_device_put(spdev); \
+ return ret; \
+} \
+ \
+static struct platform_driver __drv = { \
+ .driver = { \
+ .name = #__tag "_transport", \
+ .of_match_table = __match, \
+ }, \
+ .probe = __tag##_probe, \
+}
void scmi_notification_instance_data_set(const struct scmi_handle *handle,
void *priv);