summaryrefslogtreecommitdiffstats
path: root/meta-egvirt/recipes-kernel/linux/linux-yocto/virtio-scmi/0003-firmware-arm_scmi-Add-op-to-override-max-message.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-egvirt/recipes-kernel/linux/linux-yocto/virtio-scmi/0003-firmware-arm_scmi-Add-op-to-override-max-message.patch')
-rw-r--r--meta-egvirt/recipes-kernel/linux/linux-yocto/virtio-scmi/0003-firmware-arm_scmi-Add-op-to-override-max-message.patch165
1 files changed, 165 insertions, 0 deletions
diff --git a/meta-egvirt/recipes-kernel/linux/linux-yocto/virtio-scmi/0003-firmware-arm_scmi-Add-op-to-override-max-message.patch b/meta-egvirt/recipes-kernel/linux/linux-yocto/virtio-scmi/0003-firmware-arm_scmi-Add-op-to-override-max-message.patch
new file mode 100644
index 00000000..f58d6d88
--- /dev/null
+++ b/meta-egvirt/recipes-kernel/linux/linux-yocto/virtio-scmi/0003-firmware-arm_scmi-Add-op-to-override-max-message.patch
@@ -0,0 +1,165 @@
+From 9ffe778acc541cec68c954f84c6fcfef8a35bec2 Mon Sep 17 00:00:00 2001
+From: Igor Skalkin <igor.skalkin@opensynergy.com>
+Date: Thu, 5 Nov 2020 22:21:09 +0100
+Subject: [PATCH] firmware: arm_scmi: Add op to override max message #
+
+The number of messages that the upcoming scmi-virtio transport can
+support depends on the virtio device (SCMI platform) and can differ for
+each channel. (The scmi-virtio transport does only have one tx and at
+most 1 rx channel.)
+
+Add an optional transport op so that scmi-virtio can report the actual
+max message # for each channel type. Respect these new limits.
+
+Co-developed-by: Peter Hilber <peter.hilber@opensynergy.com>
+Signed-off-by: Peter Hilber <peter.hilber@opensynergy.com>
+Signed-off-by: Igor Skalkin <igor.skalkin@opensynergy.com>
+Signed-off-by: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+---
+ drivers/firmware/arm_scmi/common.h | 8 ++++-
+ drivers/firmware/arm_scmi/driver.c | 49 ++++++++++++++++++++++--------
+ 2 files changed, 43 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
+index 38e6aabbe3dd..9a8359ecd220 100644
+--- a/drivers/firmware/arm_scmi/common.h
++++ b/drivers/firmware/arm_scmi/common.h
+@@ -203,6 +203,9 @@ struct scmi_chan_info {
+ * @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
++ * @get_max_msg: Optional callback to provide max_msg dynamically
++ * @max_msg: Maximum number of messages for the channel type (tx or rx)
++ * that can be pending simultaneously in the system
+ * @send_message: Callback to send a message
+ * @mark_txdone: Callback to mark tx as done
+ * @fetch_response: Callback to fetch response
+@@ -215,6 +218,8 @@ struct scmi_transport_ops {
+ int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev,
+ bool tx);
+ int (*chan_free)(int id, void *p, void *data);
++ int (*get_max_msg)(bool tx, struct scmi_chan_info *base_cinfo,
++ int *max_msg);
+ int (*send_message)(struct scmi_chan_info *cinfo,
+ struct scmi_xfer *xfer);
+ void (*mark_txdone)(struct scmi_chan_info *cinfo, int ret);
+@@ -232,7 +237,8 @@ struct scmi_transport_ops {
+ * @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
++ * 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.
+ */
+ struct scmi_desc {
+diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
+index 7efbf66f117b..5baa23789a49 100644
+--- a/drivers/firmware/arm_scmi/driver.c
++++ b/drivers/firmware/arm_scmi/driver.c
+@@ -61,11 +61,13 @@ static atomic_t transfer_last_id;
+ * Index of this bitmap table is also used for message
+ * sequence identifier.
+ * @xfer_lock: Protection for message allocation
++ * @max_msg: Maximum number of messages that can be pending
+ */
+ struct scmi_xfers_info {
+ struct scmi_xfer *xfer_block;
+ unsigned long *xfer_alloc_table;
+ spinlock_t xfer_lock;
++ int max_msg;
+ };
+
+ /**
+@@ -157,13 +159,11 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle,
+ u16 xfer_id;
+ struct scmi_xfer *xfer;
+ unsigned long flags, bit_pos;
+- struct scmi_info *info = handle_to_scmi_info(handle);
+
+ /* Keep the locked section as small as possible */
+ spin_lock_irqsave(&minfo->xfer_lock, flags);
+- bit_pos = find_first_zero_bit(minfo->xfer_alloc_table,
+- info->desc->max_msg);
+- if (bit_pos == info->desc->max_msg) {
++ bit_pos = find_first_zero_bit(minfo->xfer_alloc_table, minfo->max_msg);
++ if (bit_pos == minfo->max_msg) {
+ spin_unlock_irqrestore(&minfo->xfer_lock, flags);
+ return ERR_PTR(-ENOMEM);
+ }
+@@ -602,32 +602,44 @@ int scmi_handle_put(const struct scmi_handle *handle)
+ }
+
+ static int __scmi_xfer_info_init(struct scmi_info *sinfo,
+- struct scmi_xfers_info *info)
++ struct scmi_xfers_info *info,
++ bool tx,
++ struct scmi_chan_info *base_cinfo)
+ {
+ int i;
+ struct scmi_xfer *xfer;
+ struct device *dev = sinfo->dev;
+ const struct scmi_desc *desc = sinfo->desc;
+
++ info->max_msg = desc->max_msg;
++
++ if (desc->ops->get_max_msg) {
++ int ret =
++ desc->ops->get_max_msg(tx, base_cinfo, &info->max_msg);
++
++ if (ret)
++ return ret;
++ }
++
+ /* Pre-allocated messages, no more than what hdr.seq can support */
+- if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) {
++ if (WARN_ON(info->max_msg >= MSG_TOKEN_MAX)) {
+ dev_err(dev, "Maximum message of %d exceeds supported %ld\n",
+- desc->max_msg, MSG_TOKEN_MAX);
++ info->max_msg, MSG_TOKEN_MAX);
+ return -EINVAL;
+ }
+
+- info->xfer_block = devm_kcalloc(dev, desc->max_msg,
++ info->xfer_block = devm_kcalloc(dev, info->max_msg,
+ sizeof(*info->xfer_block), GFP_KERNEL);
+ if (!info->xfer_block)
+ return -ENOMEM;
+
+- info->xfer_alloc_table = devm_kcalloc(dev, BITS_TO_LONGS(desc->max_msg),
++ info->xfer_alloc_table = devm_kcalloc(dev, BITS_TO_LONGS(info->max_msg),
+ sizeof(long), GFP_KERNEL);
+ if (!info->xfer_alloc_table)
+ return -ENOMEM;
+
+ /* Pre-initialize the buffer pointer to pre-allocated buffers */
+- for (i = 0, xfer = info->xfer_block; i < desc->max_msg; i++, xfer++) {
++ for (i = 0, xfer = info->xfer_block; i < info->max_msg; i++, xfer++) {
+ xfer->rx.buf = devm_kcalloc(dev, sizeof(u8), desc->max_msg_size,
+ GFP_KERNEL);
+ if (!xfer->rx.buf)
+@@ -644,10 +656,21 @@ static int __scmi_xfer_info_init(struct scmi_info *sinfo,
+
+ static int scmi_xfer_info_init(struct scmi_info *sinfo)
+ {
+- int ret = __scmi_xfer_info_init(sinfo, &sinfo->tx_minfo);
++ int ret;
++ struct scmi_chan_info *base_tx_cinfo;
++ struct scmi_chan_info *base_rx_cinfo;
++
++ base_tx_cinfo = idr_find(&sinfo->tx_idr, SCMI_PROTOCOL_BASE);
++ if (unlikely(!base_tx_cinfo))
++ return -EINVAL;
++
++ ret = __scmi_xfer_info_init(sinfo, &sinfo->tx_minfo, true,
++ base_tx_cinfo);
+
+- if (!ret && idr_find(&sinfo->rx_idr, SCMI_PROTOCOL_BASE))
+- ret = __scmi_xfer_info_init(sinfo, &sinfo->rx_minfo);
++ base_rx_cinfo = idr_find(&sinfo->rx_idr, SCMI_PROTOCOL_BASE);
++ if (!ret && base_rx_cinfo)
++ ret = __scmi_xfer_info_init(sinfo, &sinfo->rx_minfo, false,
++ base_rx_cinfo);
+
+ return ret;
+ }