From nobody Thu Apr 11 09:59:31 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VFZtC72Nxz5H7S7; Thu, 11 Apr 2024 09:59:31 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4VFZtC5hZ6z4lLF; Thu, 11 Apr 2024 09:59:31 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712829571; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Lta9s7mv224OvXv8eu1ywWISNU7aJekuR8Kf9yjaYKQ=; b=VllPOF9hwNYaz5XurRP0reQHY9A/k87COwmscLznq2+P68zEkitbONlGKD/W34YQoB1796 +/EU74cL1+IP7yRu8vW8B29Cu3p5dv3rcukQm/jlw/sUIBBWVyyPx6q4YkSnNIntEhvbhu g72O6fSvjg1CpkqCz8Y/xN7jp6gtwTfnVi8lq+3tJxUcCuhwlUKXAvLiTTmcrRVZp8Ib4I vM5j7kWqtTdZ53RrvNDIY5w1CveA4vjL1TMSQl9EmphKFdo385bOTYsoiJHX15YABiHjOY LQLxO+uzOlgd0KHOTCKzwrc+gW/pqcrkuHr1Vm7bgrBtYysqd9ZJ0ZhGJ79p3Q== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1712829571; a=rsa-sha256; cv=none; b=f0lpHTWJDZ300OvvPy65tm4OodFR8Y7jPbrGKlrPhctylt6ES+YQ/PM+WdDe6k1VrfHzTe 6iTvUrEDgSJRkLwpsUriK7jhxK9CMVXBmhd4/QWi3MxXlJoRchqC7HNaZM0sBa2Q/sZEXV jvv2MFRZSGUU0fjrXW8G+ECqRAzd+S+sTfEI6XFPr2tlCo3wKo7ZED6yxu+ZItcZ8sxouE Ep4iGDVx/WzGaCL6sxPzLMpK55/KueSrrlJmq/kUY5/Gh0P2G2LWnLNA1yjyJqibThpzX+ NXVDkOKDb0mCLgOb7E3KAakIXd2HfZI00dZ51cDdyD+pC3nPd8zubwoDhkDeXg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712829571; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Lta9s7mv224OvXv8eu1ywWISNU7aJekuR8Kf9yjaYKQ=; b=cQx7MyiW6B7JJVtr0B/14RIo7b+8q8QSXFE0tfPbVXy0QNbSYqmBdxpB/nLhF//h9NxR3Q JbiM/rYaUSCJGJYW28+Zxdo279GamcBe20alnUS7T2vH06y80DfSLuz0/r+V17kVRvsWxg fniRSto1uPd+dCwngDrCy5Qs1TUWEA0RIUrCHxmdTBxNT5oL5zmQWuanvdqPxV/Had9gOo j4F2ugmD34Jqr2X9FiKLbOLaGZQSdNrIBS7G53WsLRLX7t0//k0Q94xkE8cYYVEjlwI9f9 UK/gSvsMO2nP90j8OuzwlUyo1VoyCqTenK9NcxRnCXJo0s2JQta/NXHrFEc/og== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4VFZtC5HRTz1FwT; Thu, 11 Apr 2024 09:59:31 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 43B9xVT8090853; Thu, 11 Apr 2024 09:59:31 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 43B9xVBJ090851; Thu, 11 Apr 2024 09:59:31 GMT (envelope-from git) Date: Thu, 11 Apr 2024 09:59:31 GMT Message-Id: <202404110959.43B9xVBJ090851@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Andrew Turner Subject: git: a87dd74125d2 - main - scmi: Add an SCMI VirtIO transport driver List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: dev-commits-src-all+owner@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: andrew X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: a87dd74125d290791d7259ceeab9507bada9987e Auto-Submitted: auto-generated The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=a87dd74125d290791d7259ceeab9507bada9987e commit a87dd74125d290791d7259ceeab9507bada9987e Author: Cristian Marussi AuthorDate: 2023-10-23 18:07:06 +0000 Commit: Andrew Turner CommitDate: 2024-04-11 09:58:57 +0000 scmi: Add an SCMI VirtIO transport driver Add an SCMI transport driver based on the virtio-scmi backend. Reviewed by: andrew, bryanv Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D43048 --- sys/conf/files.arm64 | 1 + sys/dev/firmware/arm/scmi.c | 15 +- sys/dev/firmware/arm/scmi.h | 2 + sys/dev/firmware/arm/scmi_virtio.c | 298 +++++++++++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+), 3 deletions(-) diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index a22ffa2b7f0c..632fbab5070d 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -275,6 +275,7 @@ dev/firmware/arm/scmi_clk.c optional fdt scmi dev/firmware/arm/scmi_if.m optional fdt scmi dev/firmware/arm/scmi_mailbox.c optional fdt scmi dev/firmware/arm/scmi_smc.c optional fdt scmi +dev/firmware/arm/scmi_virtio.c optional fdt scmi dev/firmware/arm/scmi_shmem.c optional fdt scmi dev/gpio/pl061.c optional pl061 gpio diff --git a/sys/dev/firmware/arm/scmi.c b/sys/dev/firmware/arm/scmi.c index 945c2b2e9f6e..ef4bcbf13996 100644 --- a/sys/dev/firmware/arm/scmi.c +++ b/sys/dev/firmware/arm/scmi.c @@ -484,10 +484,19 @@ scmi_process_response(struct scmi_softc *sc, uint32_t hdr) mtx_lock_spin(&req->mtx); req->done = true; - if (!req->timed_out) - wakeup(req); - else + if (!req->timed_out) { + /* + * Consider the case in which a polled message is picked + * by chance on the IRQ path on another CPU: setting poll_done + * will terminate the other poll loop. + */ + if (!req->msg.polling) + wakeup(req); + else + atomic_store_rel_int(&req->msg.poll_done, 1); + } else { timed_out = true; + } mtx_unlock_spin(&req->mtx); if (timed_out) diff --git a/sys/dev/firmware/arm/scmi.h b/sys/dev/firmware/arm/scmi.h index 572422594292..345ae6eeb03a 100644 --- a/sys/dev/firmware/arm/scmi.h +++ b/sys/dev/firmware/arm/scmi.h @@ -62,12 +62,14 @@ struct scmi_softc { struct scmi_msg { bool polling; + int poll_done; uint32_t tx_len; uint32_t rx_len; #define SCMI_MSG_HDR_SIZE (sizeof(uint32_t)) uint32_t hdr; uint8_t payld[]; }; +#define hdr_to_msg(h) __containerof((h), struct scmi_msg, hdr) void *scmi_buf_get(device_t dev, uint8_t protocol_id, uint8_t message_id, int tx_payd_sz, int rx_payld_sz); diff --git a/sys/dev/firmware/arm/scmi_virtio.c b/sys/dev/firmware/arm/scmi_virtio.c new file mode 100644 index 000000000000..12cbb9ecefd5 --- /dev/null +++ b/sys/dev/firmware/arm/scmi_virtio.c @@ -0,0 +1,298 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Arm Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "scmi.h" +#include "scmi_protocols.h" + +#define SCMI_VIRTIO_POLLING_INTERVAL_MS 2 + +struct scmi_virtio_softc { + struct scmi_softc base; + device_t virtio_dev; + int cmdq_sz; + int evtq_sz; + void *p2a_pool; +}; + +static void scmi_virtio_callback(void *, unsigned int, void *); +static void *scmi_virtio_p2a_pool_init(device_t, unsigned int); +static int scmi_virtio_transport_init(device_t); +static void scmi_virtio_transport_cleanup(device_t); +static int scmi_virtio_xfer_msg(device_t, struct scmi_msg *); +static int scmi_virtio_poll_msg(device_t, struct scmi_msg *, unsigned int); +static void scmi_virtio_clear_channel(device_t, void *); +static int scmi_virtio_probe(device_t); +static int scmi_virtio_attach(device_t); + +static void +scmi_virtio_callback(void *msg, unsigned int len, void *priv) +{ + struct scmi_virtio_softc *sc; + uint32_t hdr; + + sc = priv; + + if (msg == NULL || len < sizeof(hdr)) { + device_printf(sc->virtio_dev, "Ignoring malformed message.\n"); + return; + } + + hdr = le32toh(*((uint32_t *)msg)); + scmi_rx_irq_callback(sc->base.dev, msg, hdr); +} + +static void * +scmi_virtio_p2a_pool_init(device_t dev, unsigned int max_msg) +{ + struct scmi_virtio_softc *sc; + void *pool; + uint8_t *buf; + int i; + + sc = device_get_softc(dev); + + pool = mallocarray(max_msg, SCMI_MAX_MSG_SIZE, M_DEVBUF, + M_ZERO | M_WAITOK); + + for (i = 0, buf = pool; i < max_msg; i++, buf += SCMI_MAX_MSG_SIZE) { + /* Feed platform with pre-allocated P2A buffers */ + virtio_scmi_message_enqueue(sc->virtio_dev, + VIRTIO_SCMI_CHAN_P2A, buf, 0, SCMI_MAX_MSG_SIZE); + } + + device_printf(dev, + "Fed %d initial P2A buffers to platform.\n", max_msg); + + return (pool); +} + +static void +scmi_virtio_clear_channel(device_t dev, void *msg) +{ + struct scmi_virtio_softc *sc; + + sc = device_get_softc(dev); + virtio_scmi_message_enqueue(sc->virtio_dev, VIRTIO_SCMI_CHAN_P2A, + msg, 0, SCMI_MAX_MSG_SIZE); +} + +static int +scmi_virtio_transport_init(device_t dev) +{ + struct scmi_virtio_softc *sc; + int ret; + + sc = device_get_softc(dev); + + sc->cmdq_sz = virtio_scmi_channel_size_get(sc->virtio_dev, + VIRTIO_SCMI_CHAN_A2P); + sc->evtq_sz = virtio_scmi_channel_size_get(sc->virtio_dev, + VIRTIO_SCMI_CHAN_P2A); + + if (!sc->cmdq_sz) { + device_printf(dev, + "VirtIO cmdq virtqueue not found. Aborting.\n"); + return (ENXIO); + } + + /* + * P2A buffers are owned by the platform initially; allocate a feed an + * appropriate number of buffers. + */ + if (sc->evtq_sz != 0) { + sc->p2a_pool = scmi_virtio_p2a_pool_init(dev, sc->evtq_sz); + if (sc->p2a_pool == NULL) + return (ENOMEM); + } + + /* Note that setting a callback also enables that VQ interrupts */ + ret = virtio_scmi_channel_callback_set(sc->virtio_dev, + VIRTIO_SCMI_CHAN_A2P, scmi_virtio_callback, sc); + if (ret) { + device_printf(dev, "Failed to set VirtIO cmdq callback.\n"); + return (ENXIO); + } + + device_printf(dev, + "VirtIO cmdq virtqueue configured - cmdq_sz:%d\n", sc->cmdq_sz); + + /* P2A channel is optional */ + if (sc->evtq_sz) { + ret = virtio_scmi_channel_callback_set(sc->virtio_dev, + VIRTIO_SCMI_CHAN_P2A, scmi_virtio_callback, sc); + if (ret == 0) { + device_printf(dev, + "VirtIO evtq virtqueue configured - evtq_sz:%d\n", + sc->evtq_sz); + } else { + device_printf(dev, + "Failed to set VirtIO evtq callback.Skip.\n"); + sc->evtq_sz = 0; + } + } + + sc->base.trs_desc.reply_timo_ms = 100; + + return (0); +} + +static void +scmi_virtio_transport_cleanup(device_t dev) +{ + struct scmi_virtio_softc *sc; + + sc = device_get_softc(dev); + + if (sc->evtq_sz != 0) { + virtio_scmi_channel_callback_set(sc->virtio_dev, + VIRTIO_SCMI_CHAN_P2A, NULL, NULL); + free(sc->p2a_pool, M_DEVBUF); + } + + virtio_scmi_channel_callback_set(sc->virtio_dev, + VIRTIO_SCMI_CHAN_A2P, NULL, NULL); +} + +static int +scmi_virtio_xfer_msg(device_t dev, struct scmi_msg *msg) +{ + struct scmi_virtio_softc *sc; + + sc = device_get_softc(dev); + + return (virtio_scmi_message_enqueue(sc->virtio_dev, + VIRTIO_SCMI_CHAN_A2P, &msg->hdr, msg->tx_len, msg->rx_len)); +} + +static int +scmi_virtio_poll_msg(device_t dev, struct scmi_msg *msg, unsigned int tmo_ms) +{ + struct scmi_virtio_softc *sc; + device_t vdev; + int tmo_loops; + + sc = device_get_softc(dev); + vdev = sc->virtio_dev; + + tmo_loops = tmo_ms / SCMI_VIRTIO_POLLING_INTERVAL_MS; + while (tmo_loops-- && atomic_load_acq_int(&msg->poll_done) == 0) { + struct scmi_msg *rx_msg; + void *rx_buf; + uint32_t rx_len; + + rx_buf = virtio_scmi_message_poll(vdev, &rx_len); + if (rx_buf == NULL) { + DELAY(SCMI_VIRTIO_POLLING_INTERVAL_MS * 1000); + continue; + } + + rx_msg = hdr_to_msg(rx_buf); + rx_msg->rx_len = rx_len; + /* Complete the polling on any poll path */ + if (rx_msg->polling) + atomic_store_rel_int(&rx_msg->poll_done, 1); + + if (__predict_true(rx_msg == msg)) + break; + + /* + * Polling returned an unexpected message: either a message + * polled by some other thread of execution or a message not + * supposed to be polled. + */ + device_printf(dev, "POLLED OoO HDR:|%08X| - polling:%d\n", + rx_msg->hdr, rx_msg->polling); + + if (!rx_msg->polling) + scmi_rx_irq_callback(sc->base.dev, rx_msg, rx_msg->hdr); + } + + return (tmo_loops > 0 ? 0 : ETIMEDOUT); +} + +static int +scmi_virtio_probe(device_t dev) +{ + if (!ofw_bus_is_compatible(dev, "arm,scmi-virtio")) + return (ENXIO); + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + device_set_desc(dev, "ARM SCMI VirtIO Transport driver"); + + return (BUS_PROBE_DEFAULT); +} + +static int +scmi_virtio_attach(device_t dev) +{ + struct scmi_virtio_softc *sc; + + sc = device_get_softc(dev); + sc->virtio_dev = virtio_scmi_transport_get(); + if (sc->virtio_dev == NULL) + return (1); + + /* When attach fails there is nothing to cleanup*/ + return (scmi_attach(dev)); +} + +static device_method_t scmi_virtio_methods[] = { + DEVMETHOD(device_probe, scmi_virtio_probe), + DEVMETHOD(device_attach, scmi_virtio_attach), + + /* SCMI interface */ + DEVMETHOD(scmi_transport_init, scmi_virtio_transport_init), + DEVMETHOD(scmi_transport_cleanup, scmi_virtio_transport_cleanup), + DEVMETHOD(scmi_xfer_msg, scmi_virtio_xfer_msg), + DEVMETHOD(scmi_poll_msg, scmi_virtio_poll_msg), + DEVMETHOD(scmi_clear_channel, scmi_virtio_clear_channel), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(scmi_virtio, scmi_virtio_driver, scmi_virtio_methods, + sizeof(struct scmi_virtio_softc), scmi_driver); + +/* Needs to be after the mmio_sram driver */ +DRIVER_MODULE(scmi_virtio, simplebus, scmi_virtio_driver, 0, 0); +MODULE_VERSION(scmi_virtio, 1);