The branch main has been updated by andrew:

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

commit 403ca28c28bdd34849b7e621b5e0acb4a864111c
Author:     Cristian Marussi <[email protected]>
AuthorDate: 2023-12-07 14:06:36 +0000
Commit:     Andrew Turner <[email protected]>
CommitDate: 2024-04-11 09:58:56 +0000

    scmi: Add new SCMI interfaces for init and message processing
    
    Introduce a couple of new SCMI interface methods to allow centralized
    initialization of transport-specific features and a couple of methods
    to handle message reception from the SCMI core.
    
    Move SCMI SMT related calls out of the core common SCMI code into the
    transport specific layers Mailbox/SMC.
    
    Make SCMI Mailbox/SMC transports use the new interface methods for
    initialization and message reception.
    
    Reviewed by:    andrew
    Tested on:      Arm Morello Board
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D43044
---
 sys/dev/firmware/arm/scmi.c         |  42 +++---------
 sys/dev/firmware/arm/scmi.h         |   1 -
 sys/dev/firmware/arm/scmi_if.m      |  23 +++++++
 sys/dev/firmware/arm/scmi_mailbox.c | 127 +++++++++++++++++++++++++-----------
 sys/dev/firmware/arm/scmi_shmem.c   |   2 +-
 sys/dev/firmware/arm/scmi_smc.c     |  78 +++++++++++++++++++---
 6 files changed, 192 insertions(+), 81 deletions(-)

diff --git a/sys/dev/firmware/arm/scmi.c b/sys/dev/firmware/arm/scmi.c
index a797e52d74b1..5a69dc1daa7b 100644
--- a/sys/dev/firmware/arm/scmi.c
+++ b/sys/dev/firmware/arm/scmi.c
@@ -43,11 +43,8 @@
 #include <dev/fdt/fdt_common.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
-#include "dev/mailbox/arm/arm_doorbell.h"
-
 #include "scmi.h"
 #include "scmi_protocols.h"
-#include "scmi_shmem.h"
 
 #define        SCMI_HDR_TOKEN_S                18
 #define SCMI_HDR_TOKEN_BF              (0x3fff)
@@ -75,7 +72,6 @@
 static int
 scmi_request_locked(struct scmi_softc *sc, struct scmi_req *req)
 {
-       uint32_t reply_header;
        int ret;
 
        SCMI_ASSERT_LOCKED(sc);
@@ -85,29 +81,12 @@ 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, cold);
-       if (ret != 0)
-               return (ret);
-
-       ret = SCMI_XFER_MSG(sc->dev);
-       if (ret != 0)
-               goto out;
-
-       /* Read header. */
-       ret = scmi_shmem_read_msg_header(sc->a2p_dev, &reply_header);
-       if (ret != 0)
-               goto out;
-
-       if (reply_header != req->msg_header) {
-               ret = EPROTO;
-               goto out;
-       }
+       ret = SCMI_XFER_MSG(sc->dev, req);
+       if (ret == 0)
+               ret = SCMI_COLLECT_REPLY(sc->dev, req);
 
-       ret = scmi_shmem_read_msg_payload(sc->a2p_dev, req->out_buf,
-           req->out_size);
-
-out:
-       scmi_shmem_tx_complete(sc->a2p_dev);
+       if (ret == 0  || ret != EBUSY)
+               SCMI_TX_COMPLETE(sc->dev, NULL);
 
        return (ret);
 }
@@ -141,16 +120,14 @@ scmi_attach(device_t dev)
        if (node == -1)
                return (ENXIO);
 
-       sc->a2p_dev = scmi_shmem_get(dev, node, SCMI_CHAN_A2P);
-       if (sc->a2p_dev == NULL) {
-               device_printf(dev, "A2P shmem dev not found.\n");
-               return (ENXIO);
-       }
-
        mtx_init(&sc->mtx, device_get_nameunit(dev), "SCMI", MTX_DEF);
 
        simplebus_init(dev, node);
 
+       error = SCMI_TRANSPORT_INIT(dev);
+       if (error != 0)
+               return (error);
+
        /*
         * Allow devices to identify.
         */
@@ -171,6 +148,7 @@ static int
 scmi_detach(device_t dev)
 {
 
+       SCMI_TRANSPORT_CLEANUP(dev);
        return (0);
 }
 
diff --git a/sys/dev/firmware/arm/scmi.h b/sys/dev/firmware/arm/scmi.h
index bebebff50429..2647db9d9e90 100644
--- a/sys/dev/firmware/arm/scmi.h
+++ b/sys/dev/firmware/arm/scmi.h
@@ -51,7 +51,6 @@ enum scmi_chan {
 struct scmi_softc {
        struct simplebus_softc  simplebus_sc;
        device_t                dev;
-       device_t                a2p_dev;
        struct mtx              mtx;
 };
 
diff --git a/sys/dev/firmware/arm/scmi_if.m b/sys/dev/firmware/arm/scmi_if.m
index 524cf0fb0d66..5cacf99edc47 100644
--- a/sys/dev/firmware/arm/scmi_if.m
+++ b/sys/dev/firmware/arm/scmi_if.m
@@ -27,6 +27,29 @@
 
 INTERFACE scmi;
 
+HEADER {
+       struct scmi_req;
+};
+
+METHOD int transport_init {
+       device_t dev;
+};
+
+METHOD void transport_cleanup {
+       device_t dev;
+};
+
 METHOD int xfer_msg {
        device_t dev;
+       struct scmi_req *req;
+};
+
+METHOD int collect_reply {
+       device_t dev;
+       struct scmi_req *req;
+};
+
+METHOD void tx_complete {
+       device_t dev;
+       void *chan;
 };
diff --git a/sys/dev/firmware/arm/scmi_mailbox.c 
b/sys/dev/firmware/arm/scmi_mailbox.c
index c7f4fda4d5c4..fa2b196478cd 100644
--- a/sys/dev/firmware/arm/scmi_mailbox.c
+++ b/sys/dev/firmware/arm/scmi_mailbox.c
@@ -53,10 +53,19 @@
 
 struct scmi_mailbox_softc {
        struct scmi_softc       base;
+       device_t                a2p_dev;
        struct arm_doorbell     *db;
        int                     req_done;
 };
 
+static int     scmi_mailbox_transport_init(device_t);
+static void    scmi_mailbox_transport_cleanup(device_t);
+static int     scmi_mailbox_xfer_msg(device_t, struct scmi_req *);
+static int     scmi_mailbox_collect_reply(device_t, struct scmi_req *);
+static void    scmi_mailbox_tx_complete(device_t, void *);
+
+static int     scmi_mailbox_probe(device_t);
+
 static void
 scmi_mailbox_callback(void *arg)
 {
@@ -73,16 +82,64 @@ scmi_mailbox_callback(void *arg)
 }
 
 static int
-scmi_mailbox_xfer_msg(device_t dev)
+scmi_mailbox_transport_init(device_t dev)
+{
+       struct scmi_mailbox_softc *sc;
+       phandle_t node;
+
+       sc = device_get_softc(dev);
+
+       node = ofw_bus_get_node(dev);
+       if (node == -1)
+               return (ENXIO);
+       /*
+        * TODO
+        * - Support P2A shmem + IRQ/doorbell
+        * - Support other mailbox devices
+        */
+       sc->a2p_dev = scmi_shmem_get(dev, node, SCMI_CHAN_A2P);
+       if (sc->a2p_dev == NULL) {
+               device_printf(dev, "A2P shmem dev not found.\n");
+               return (ENXIO);
+       }
+
+       /* TODO: Fix ofw_get...mbox doorbell names NOT required in Linux DT */
+       sc->db = arm_doorbell_ofw_get(dev, "tx");
+       if (sc->db == NULL) {
+               device_printf(dev, "Doorbell device not found.\n");
+               return (ENXIO);
+       }
+
+       arm_doorbell_set_handler(sc->db, scmi_mailbox_callback, sc);
+
+       return (0);
+}
+
+static void
+scmi_mailbox_transport_cleanup(device_t dev)
+{
+       struct scmi_mailbox_softc *sc;
+
+       sc = device_get_softc(dev);
+
+       arm_doorbell_set_handler(sc->db, NULL, NULL);
+}
+
+static int
+scmi_mailbox_xfer_msg(device_t dev, struct scmi_req *req)
 {
        struct scmi_mailbox_softc *sc;
-       int timeout;
+       int ret, timeout;
 
        sc = device_get_softc(dev);
        SCMI_ASSERT_LOCKED(&sc->base);
 
        sc->req_done = 0;
 
+       ret = scmi_shmem_prepare_msg(sc->a2p_dev, req, cold);
+       if (ret != 0)
+               return (ret);
+
        /* Interrupt SCP firmware. */
        arm_doorbell_set(sc->db);
 
@@ -92,7 +149,7 @@ scmi_mailbox_xfer_msg(device_t dev)
 
        do {
                if (cold) {
-                       if (scmi_shmem_poll_msg(sc->base.a2p_dev))
+                       if (scmi_shmem_poll_msg(sc->a2p_dev))
                                break;
                        DELAY(10000);
                } else {
@@ -103,7 +160,7 @@ scmi_mailbox_xfer_msg(device_t dev)
        } while (timeout--);
 
        if (timeout <= 0)
-               return (-1);
+               return (ETIMEDOUT);
 
        dprintf("%s: got reply, timeout %d\n", __func__, timeout);
 
@@ -111,63 +168,59 @@ scmi_mailbox_xfer_msg(device_t dev)
 }
 
 static int
-scmi_mailbox_probe(device_t dev)
+scmi_mailbox_collect_reply(device_t dev, struct scmi_req *req)
 {
+       struct scmi_mailbox_softc *sc;
+       uint32_t reply_header;
+       int ret;
 
-       if (!ofw_bus_is_compatible(dev, "arm,scmi"))
-               return (ENXIO);
+       sc = device_get_softc(dev);
 
-       if (!ofw_bus_status_okay(dev))
-               return (ENXIO);
+       /* Read header. */
+       ret = scmi_shmem_read_msg_header(sc->a2p_dev, &reply_header);
+       if (ret != 0)
+               return (ret);
 
-       device_set_desc(dev, "ARM SCMI interface driver");
+       if (reply_header != req->msg_header)
+               return (EPROTO);
 
-       return (BUS_PROBE_DEFAULT);
+       return (scmi_shmem_read_msg_payload(sc->a2p_dev, req->out_buf,
+           req->out_size));
 }
 
-static int
-scmi_mailbox_attach(device_t dev)
+static void
+scmi_mailbox_tx_complete(device_t dev, void *chan)
 {
        struct scmi_mailbox_softc *sc;
-       int ret;
 
        sc = device_get_softc(dev);
-
-       /* TODO: Support other mailbox devices */
-       sc->db = arm_doorbell_ofw_get(dev, "tx");
-       if (sc->db == NULL) {
-               device_printf(dev, "Doorbell device not found.\n");
-               return (ENXIO);
-       }
-
-       arm_doorbell_set_handler(sc->db, scmi_mailbox_callback, sc);
-
-       ret = scmi_attach(dev);
-       if (ret != 0)
-               arm_doorbell_set_handler(sc->db, NULL, NULL);
-
-       return (ret);
+       scmi_shmem_tx_complete(sc->a2p_dev);
 }
 
 static int
-scmi_mailbox_detach(device_t dev)
+scmi_mailbox_probe(device_t dev)
 {
-       struct scmi_mailbox_softc *sc;
 
-       sc = device_get_softc(dev);
+       if (!ofw_bus_is_compatible(dev, "arm,scmi"))
+               return (ENXIO);
 
-       arm_doorbell_set_handler(sc->db, NULL, NULL);
+       if (!ofw_bus_status_okay(dev))
+               return (ENXIO);
 
-       return (0);
+       device_set_desc(dev, "ARM SCMI interface driver");
+
+       return (BUS_PROBE_DEFAULT);
 }
 
 static device_method_t scmi_mailbox_methods[] = {
        DEVMETHOD(device_probe,         scmi_mailbox_probe),
-       DEVMETHOD(device_attach,        scmi_mailbox_attach),
-       DEVMETHOD(device_detach,        scmi_mailbox_detach),
 
        /* SCMI interface */
-       DEVMETHOD(scmi_xfer_msg,        scmi_mailbox_xfer_msg),
+       DEVMETHOD(scmi_transport_init,          scmi_mailbox_transport_init),
+       DEVMETHOD(scmi_transport_cleanup,       scmi_mailbox_transport_cleanup),
+       DEVMETHOD(scmi_xfer_msg,                scmi_mailbox_xfer_msg),
+       DEVMETHOD(scmi_collect_reply,           scmi_mailbox_collect_reply),
+       DEVMETHOD(scmi_tx_complete,             scmi_mailbox_tx_complete),
 
        DEVMETHOD_END
 };
diff --git a/sys/dev/firmware/arm/scmi_shmem.c 
b/sys/dev/firmware/arm/scmi_shmem.c
index 5fb41af05246..7cb2db48f9fe 100644
--- a/sys/dev/firmware/arm/scmi_shmem.c
+++ b/sys/dev/firmware/arm/scmi_shmem.c
@@ -210,7 +210,7 @@ scmi_shmem_prepare_msg(device_t dev, struct scmi_req *req, 
bool polling)
        if ((channel_status & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE) == 0) {
                scmi_shmem_release_channel(sc);
                device_printf(dev, "Shmem channel busy. Abort !.\n");
-               return (1);
+               return (EBUSY);
        }
 
        /* Update header */
diff --git a/sys/dev/firmware/arm/scmi_smc.c b/sys/dev/firmware/arm/scmi_smc.c
index ff5f4a2d1491..e238e8024068 100644
--- a/sys/dev/firmware/arm/scmi_smc.c
+++ b/sys/dev/firmware/arm/scmi_smc.c
@@ -48,25 +48,88 @@
 
 #include "scmi.h"
 #include "scmi_protocols.h"
+#include "scmi_shmem.h"
 
 struct scmi_smc_softc {
        struct scmi_softc       base;
        uint32_t                smc_id;
+       device_t                a2p_dev;
 };
 
+static int     scmi_smc_transport_init(device_t);
+static int     scmi_smc_xfer_msg(device_t, struct scmi_req *);
+static int     scmi_smc_collect_reply(device_t, struct scmi_req *);
+static void    scmi_smc_tx_complete(device_t, void *);
+
+static int     scmi_smc_probe(device_t);
+static int     scmi_smc_attach(device_t);
+
 static int
-scmi_smc_xfer_msg(device_t dev)
+scmi_smc_transport_init(device_t dev)
 {
        struct scmi_smc_softc *sc;
+       phandle_t node;
+       ssize_t len;
+
+       sc = device_get_softc(dev);
+
+       node = ofw_bus_get_node(dev);
+       len = OF_getencprop(node, "arm,smc-id", &sc->smc_id,
+           sizeof(sc->smc_id));
+       if (len <= 0) {
+               device_printf(dev, "No SMC ID found\n");
+               return (EINVAL);
+       }
+
+       device_printf(dev, "smc id %x\n", sc->smc_id);
+
+       sc->a2p_dev = scmi_shmem_get(dev, node, SCMI_CHAN_A2P);
+       if (sc->a2p_dev == NULL) {
+               device_printf(dev, "A2P shmem dev not found.\n");
+               return (ENXIO);
+       }
+
+       return (0);
+}
+
+static int
+scmi_smc_xfer_msg(device_t dev, struct scmi_req *req)
+{
+       struct scmi_smc_softc *sc;
+       int ret;
 
        sc = device_get_softc(dev);
        SCMI_ASSERT_LOCKED(&sc->base);
 
+       ret = scmi_shmem_prepare_msg(sc->a2p_dev, req, cold);
+       if (ret != 0)
+               return (ret);
+
        arm_smccc_smc(sc->smc_id, 0, 0, 0, 0, 0, 0, 0, NULL);
 
        return (0);
 }
 
+static int
+scmi_smc_collect_reply(device_t dev, struct scmi_req *req)
+{
+       struct scmi_smc_softc *sc;
+
+       sc = device_get_softc(dev);
+
+       return (scmi_shmem_read_msg_payload(sc->a2p_dev, req->out_buf,
+           req->out_size));
+}
+
+static void
+scmi_smc_tx_complete(device_t dev, void *chan)
+{
+       struct scmi_smc_softc *sc;
+
+       sc = device_get_softc(dev);
+       scmi_shmem_tx_complete(sc->a2p_dev);
+}
+
 static int
 scmi_smc_probe(device_t dev)
 {
@@ -104,20 +167,15 @@ scmi_smc_attach(device_t dev)
        return (scmi_attach(dev));
 }
 
-static int
-scmi_smc_detach(device_t dev)
-{
-
-       return (0);
-}
-
 static device_method_t scmi_smc_methods[] = {
        DEVMETHOD(device_probe,         scmi_smc_probe),
        DEVMETHOD(device_attach,        scmi_smc_attach),
-       DEVMETHOD(device_detach,        scmi_smc_detach),
 
        /* SCMI interface */
-       DEVMETHOD(scmi_xfer_msg,        scmi_smc_xfer_msg),
+       DEVMETHOD(scmi_transport_init,          scmi_smc_transport_init),
+       DEVMETHOD(scmi_xfer_msg,                scmi_smc_xfer_msg),
+       DEVMETHOD(scmi_collect_reply,           scmi_smc_collect_reply),
+       DEVMETHOD(scmi_tx_complete,             scmi_smc_tx_complete),
 
        DEVMETHOD_END
 };

Reply via email to