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);