git: b802926b7b14 - main - scmi: Add optional asynchronous handling of replies

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Thu, 23 Jan 2025 17:27:38 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=b802926b7b145d7cfe2465ac4e19f062a9eb6e6d

commit b802926b7b145d7cfe2465ac4e19f062a9eb6e6d
Author:     Cristian Marussi <cristian.marussi@arm.com>
AuthorDate: 2025-01-23 13:26:12 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2025-01-23 17:26:27 +0000

    scmi: Add optional asynchronous handling of replies
    
    Add the core logic to handle the replies to pending command in an
    asynchronous manner.
    
    Tested on:      Arm Morello Board
    Reviewed by:    andrew
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D47426
    Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 sys/dev/firmware/arm/scmi.c | 46 ++++++++++++++++++++++++++++++++++++++++-----
 sys/dev/firmware/arm/scmi.h |  1 +
 2 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/sys/dev/firmware/arm/scmi.c b/sys/dev/firmware/arm/scmi.c
index 950bbf94eeb6..0b165e413674 100644
--- a/sys/dev/firmware/arm/scmi.c
+++ b/sys/dev/firmware/arm/scmi.c
@@ -43,6 +43,7 @@
 #include <sys/mutex.h>
 #include <sys/queue.h>
 #include <sys/refcount.h>
+#include <sys/taskqueue.h>
 
 #include <dev/clk/clk.h>
 #include <dev/fdt/simplebus.h>
@@ -94,6 +95,8 @@ struct scmi_req {
 	bool		use_polling;
 	bool		done;
 	bool		is_raw;
+	device_t	dev;
+	struct task	tsk;
 	struct mtx	mtx;
 	LIST_ENTRY(scmi_req)	next;
 	int		protocol_id;
@@ -103,6 +106,7 @@ struct scmi_req {
 	struct scmi_msg msg;
 };
 
+#define tsk_to_req(t)	__containerof((t), struct scmi_req, tsk)
 #define buf_to_msg(b)	__containerof((b), struct scmi_msg, payld)
 #define msg_to_req(m)	__containerof((m), struct scmi_req, msg)
 #define buf_to_req(b)	msg_to_req(buf_to_msg(b))
@@ -131,7 +135,9 @@ struct scmi_transport {
 static void		scmi_transport_configure(struct scmi_transport_desc *, phandle_t);
 static int		scmi_transport_init(struct scmi_softc *, phandle_t);
 static void		scmi_transport_cleanup(struct scmi_softc *);
-static struct scmi_reqs_pool *scmi_reqs_pool_allocate(const int, const int);
+static void		scmi_req_async_waiter(void *, int);
+static struct scmi_reqs_pool *scmi_reqs_pool_allocate(device_t, const int,
+			    const int);
 static void		scmi_reqs_pool_free(struct scmi_reqs_pool *);
 static struct scmi_req	*scmi_req_alloc(struct scmi_softc *, enum scmi_chan);
 static struct scmi_req	*scmi_req_initialized_alloc(device_t, int, int);
@@ -217,7 +223,7 @@ DRIVER_MODULE(scmi, simplebus, scmi_driver, 0, 0);
 MODULE_VERSION(scmi, 1);
 
 static struct scmi_reqs_pool *
-scmi_reqs_pool_allocate(const int max_msg, const int max_payld_sz)
+scmi_reqs_pool_allocate(device_t dev, const int max_msg, const int max_payld_sz)
 {
 	struct scmi_reqs_pool *rp;
 	struct scmi_req *req;
@@ -229,6 +235,10 @@ scmi_reqs_pool_allocate(const int max_msg, const int max_payld_sz)
 		req = malloc(sizeof(*req) + max_payld_sz,
 		    M_DEVBUF, M_ZERO | M_WAITOK);
 
+		req->dev = dev;
+		req->tsk.ta_context = &req->tsk;
+		req->tsk.ta_func = scmi_req_async_waiter;
+
 		mtx_init(&req->mtx, "req", "SCMI", MTX_SPIN);
 		LIST_INSERT_HEAD(&rp->head, req, next);
 	}
@@ -280,14 +290,14 @@ scmi_transport_init(struct scmi_softc *sc, phandle_t node)
 	trs->inflight_ht = hashinit(td->max_msg, M_DEVBUF, &trs->inflight_mask);
 
 	trs->chans[SCMI_CHAN_A2P] =
-	    scmi_reqs_pool_allocate(td->max_msg, td->max_payld_sz);
+	    scmi_reqs_pool_allocate(sc->dev, td->max_msg, td->max_payld_sz);
 	if (trs->chans[SCMI_CHAN_A2P] == NULL) {
 		free(trs, M_DEVBUF);
 		return (ENOMEM);
 	}
 
 	trs->chans[SCMI_CHAN_P2A] =
-	    scmi_reqs_pool_allocate(td->max_msg, td->max_payld_sz);
+	    scmi_reqs_pool_allocate(sc->dev, td->max_msg, td->max_payld_sz);
 	if (trs->chans[SCMI_CHAN_P2A] == NULL) {
 		scmi_reqs_pool_free(trs->chans[SCMI_CHAN_A2P]);
 		free(trs, M_DEVBUF);
@@ -648,7 +658,8 @@ scmi_wait_for_response(struct scmi_softc *sc, struct scmi_req *req, void **out)
 		SCMI_COLLECT_REPLY(sc->dev, &req->msg);
 		if (req->msg.payld[0] != 0)
 			ret = req->msg.payld[0];
-		*out = &req->msg.payld[SCMI_MSG_HDR_SIZE];
+		if (out != NULL)
+			*out = &req->msg.payld[SCMI_MSG_HDR_SIZE];
 	} else {
 		device_printf(sc->dev,
 		    "Request for token 0x%X timed-out.\n", req->token);
@@ -703,6 +714,20 @@ scmi_msg_get(device_t dev, int tx_payld_sz, int rx_payld_sz)
 	return (&req->msg);
 }
 
+static void
+scmi_req_async_waiter(void *context, int pending)
+{
+	struct task *ta = context;
+	struct scmi_softc *sc;
+	struct scmi_req *req;
+
+	req = tsk_to_req(ta);
+	sc = device_get_softc(req->dev);
+	scmi_wait_for_response(sc, req, NULL);
+
+	scmi_msg_put(req->dev, &req->msg);
+}
+
 void
 scmi_msg_put(device_t dev, struct scmi_msg *msg)
 {
@@ -763,3 +788,14 @@ scmi_request(device_t dev, void *in, void **out)
 
 	return (scmi_wait_for_response(sc, req, out));
 }
+
+int
+scmi_msg_async_enqueue(struct scmi_msg *msg)
+{
+	struct scmi_req *req;
+
+	req = msg_to_req(msg);
+
+	return taskqueue_enqueue_flags(taskqueue_thread, &req->tsk,
+	    TASKQUEUE_FAIL_IF_PENDING | TASKQUEUE_FAIL_IF_CANCELING);
+}
diff --git a/sys/dev/firmware/arm/scmi.h b/sys/dev/firmware/arm/scmi.h
index f5b4173272bb..990759237964 100644
--- a/sys/dev/firmware/arm/scmi.h
+++ b/sys/dev/firmware/arm/scmi.h
@@ -84,6 +84,7 @@ struct scmi_msg *scmi_msg_get(device_t dev, int tx_payld_sz, int rx_payld_sz);
 void scmi_msg_put(device_t dev, struct scmi_msg *msg);
 int scmi_request(device_t dev, void *in, void **);
 int scmi_request_tx(device_t dev, void *in);
+int scmi_msg_async_enqueue(struct scmi_msg *msg);
 void scmi_rx_irq_callback(device_t dev, void *chan, uint32_t hdr, uint32_t rx_len);
 
 DECLARE_CLASS(scmi_driver);