git: cbcfdff05678 - main - scmi: Fix SCMI mailbox polling mechanism
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 11 Apr 2024 09:59:24 UTC
The branch main has been updated by andrew:
URL: https://cgit.FreeBSD.org/src/commit/?id=cbcfdff05678b143436f81e09f21b3c727efd805
commit cbcfdff05678b143436f81e09f21b3c727efd805
Author: Cristian Marussi <cristian.marussi@arm.com>
AuthorDate: 2023-12-07 07:06:10 +0000
Commit: Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-04-11 09:58:56 +0000
scmi: Fix SCMI mailbox polling mechanism
When the system is cold, the SCMI stack processes commands in polling
mode with the current polling mechanism being a check of the status
register in the mailbox controller to see if there is any pending
doorbell request.
Anyway, the completion interrupt is optional by the SCMI specification
and a system could have been simply designed without it: for this
reason polling on the mailbox controller status registers is not going
to work in all situations.
Moreover even alternative SCMI transports based on shared memory, like
SMC, will not have at all a mailbox controller to poll for.
On the other side, the associated SCMI Shared Memory Transport defines
dedicated channel flags and status bits that can be used by the agent to
explicitly request a polling-based transaction, even if the completion
interrupt was available, and to check afterwards when the platform has
completed its processing on the outstanding command.
Use SCMI/SMT specific mechanism to process transactions in polling mode.
Reviewed by: andrew
Tested on: Arm Morello Board
Sponsored by: Arm Ltd
Differential Revision: https://reviews.freebsd.org/D43042
---
sys/dev/firmware/arm/scmi.c | 2 +-
sys/dev/firmware/arm/scmi_mailbox.c | 3 ++-
sys/dev/firmware/arm/scmi_shmem.c | 18 ++++++++++++++++--
sys/dev/firmware/arm/scmi_shmem.h | 4 +++-
4 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/sys/dev/firmware/arm/scmi.c b/sys/dev/firmware/arm/scmi.c
index 8428d17cecec..ee41ad4383c0 100644
--- a/sys/dev/firmware/arm/scmi.c
+++ b/sys/dev/firmware/arm/scmi.c
@@ -85,7 +85,7 @@ scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req)
req->msg_header |= SCMI_MSG_TYPE_CMD << SCMI_HDR_MESSAGE_TYPE_S;
req->msg_header |= req->protocol_id << SCMI_HDR_PROTOCOL_ID_S;
- ret = scmi_shmem_prepare_msg(sc->a2p_dev, req);
+ ret = scmi_shmem_prepare_msg(sc->a2p_dev, req, cold);
if (ret != 0)
return (ret);
diff --git a/sys/dev/firmware/arm/scmi_mailbox.c b/sys/dev/firmware/arm/scmi_mailbox.c
index bebdc7348b98..c7f4fda4d5c4 100644
--- a/sys/dev/firmware/arm/scmi_mailbox.c
+++ b/sys/dev/firmware/arm/scmi_mailbox.c
@@ -49,6 +49,7 @@
#include "scmi.h"
#include "scmi_protocols.h"
+#include "scmi_shmem.h"
struct scmi_mailbox_softc {
struct scmi_softc base;
@@ -91,7 +92,7 @@ scmi_mailbox_xfer_msg(device_t dev)
do {
if (cold) {
- if (arm_doorbell_get(sc->db))
+ if (scmi_shmem_poll_msg(sc->base.a2p_dev))
break;
DELAY(10000);
} else {
diff --git a/sys/dev/firmware/arm/scmi_shmem.c b/sys/dev/firmware/arm/scmi_shmem.c
index efb6b77c6e4b..066f28777cb7 100644
--- a/sys/dev/firmware/arm/scmi_shmem.c
+++ b/sys/dev/firmware/arm/scmi_shmem.c
@@ -168,7 +168,7 @@ scmi_shmem_get(device_t dev, phandle_t node, int index)
}
int
-scmi_shmem_prepare_msg(device_t dev, struct scmi_req *req)
+scmi_shmem_prepare_msg(device_t dev, struct scmi_req *req, bool polling)
{
struct scmi_smt_header hdr = {};
uint32_t channel_status;
@@ -185,7 +185,10 @@ scmi_shmem_prepare_msg(device_t dev, struct scmi_req *req)
hdr.channel_status &= ~SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE;
hdr.msg_header = htole32(req->msg_header);
hdr.length = htole32(sizeof(req->msg_header) + req->in_size);
- hdr.flags |= SCMI_SHMEM_FLAG_INTR_ENABLED;
+ if (!polling)
+ hdr.flags |= SCMI_SHMEM_FLAG_INTR_ENABLED;
+ else
+ hdr.flags &= ~SCMI_SHMEM_FLAG_INTR_ENABLED;
/* Write header */
scmi_shmem_write(dev, 0, &hdr, SMT_SIZE_HEADER);
@@ -239,6 +242,17 @@ scmi_shmem_read_msg_payload(device_t dev, uint8_t *buf, uint32_t buf_len)
return (0);
}
+bool scmi_shmem_poll_msg(device_t dev)
+{
+ uint32_t status;
+
+ scmi_shmem_read(dev, SMT_OFFSET_CHAN_STATUS, &status,
+ SMT_SIZE_CHAN_STATUS);
+
+ return (status & (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR |
+ SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE));
+}
+
static device_method_t shmem_methods[] = {
DEVMETHOD(device_probe, shmem_probe),
DEVMETHOD(device_attach, shmem_attach),
diff --git a/sys/dev/firmware/arm/scmi_shmem.h b/sys/dev/firmware/arm/scmi_shmem.h
index ce82a3c90d87..d46493dc0342 100644
--- a/sys/dev/firmware/arm/scmi_shmem.h
+++ b/sys/dev/firmware/arm/scmi_shmem.h
@@ -63,7 +63,9 @@ struct scmi_smt_header {
struct scmi_req;
device_t scmi_shmem_get(device_t sdev, phandle_t node, int index);
-int scmi_shmem_prepare_msg(device_t dev, struct scmi_req *req);
+int scmi_shmem_prepare_msg(device_t dev, struct scmi_req *req,
+ bool polling);
+bool scmi_shmem_poll_msg(device_t);
int scmi_shmem_read_msg_header(device_t dev, uint32_t *msg_header);
int scmi_shmem_read_msg_payload(device_t dev, uint8_t *buf, uint32_t buf_len);