From nobody Thu Apr 2 10:43:03 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1850A382394; Sun, 29 Mar 2026 16:34:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774802101; cv=none; b=W6XTjgG4IvPaRxEAFH2ZqP0Iay+bPhUfkLKIMnz2rJuemtZ4KueRHMWW0+Y+NVSSHH/3yEhQNjkqI/L90nXvzClXwT5c7kaXjDBow/Ki3S6Zl7Zm4UzONLLHm4e+/vlK7cayNqE1AZExVD3q8leLX7vdZ5HdtDDxSQ0wGlK8emw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774802101; c=relaxed/simple; bh=nu+fJaUxJaQsytzWpGLbAsM/VqP9ochrSIBstfIg0cU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QMZagE9mQdN1p/ik3+xxLa4sBUcDW9i20YWS4QHHK59kiXc4irTQOqdTocn+TrLWqK8r67zqgWS2Xvig1rx4gHg1xJc02pqpKgmAJtmr6YykRJxVCDVw8AXn21ZJ750CA5jRKK9GEigYI0ZAsdsBJxH4WpDOW7HY5hnCliiOK4s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=Ox5HS807; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="Ox5HS807" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 972563627; Sun, 29 Mar 2026 09:34:53 -0700 (PDT) Received: from pluto.fritz.box (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AB2C43F915; Sun, 29 Mar 2026 09:34:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1774802099; bh=nu+fJaUxJaQsytzWpGLbAsM/VqP9ochrSIBstfIg0cU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ox5HS807KIhwMsDl3OtQ02B8kbepMEyKgzRSVC5GQ9Wvx5rhM5xmteQvICkHg7iOs u6o/va0ebedNI6n37aASAor3MScCJgPyunOlKwuOh32cvQ+FxBy7g8b21KTVpJ4IRG gDPtErHWuYVkIGJUMZ7fXb/BFUSl1mGgNP9O2SRY= From: Cristian Marussi To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, arm-scmi@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-doc@vger.kernel.org Cc: sudeep.holla@kernel.org, james.quinlan@broadcom.com, f.fainelli@gmail.com, vincent.guittot@linaro.org, etienne.carriere@st.com, peng.fan@oss.nxp.com, michal.simek@amd.com, dan.carpenter@linaro.org, d-gole@ti.com, jonathan.cameron@huawei.com, elif.topuz@arm.com, lukasz.luba@arm.com, philip.radford@arm.com, brauner@kernel.org, souvik.chakravarty@arm.com, Cristian Marussi Subject: [PATCH v3 14/24] firmware: arm_scmi: Add support for boot-on Telemetry Date: Sun, 29 Mar 2026 17:33:25 +0100 Message-ID: <20260329163337.637393-15-cristian.marussi@arm.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260329163337.637393-1-cristian.marussi@arm.com> References: <20260329163337.637393-1-cristian.marussi@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the initialization and discovery logic needed to detect when the platform SCMI server is configured with telemetry enabled at boot and perform all the needed resource enumerations to keep the kernel telemetry subsystem state aligned with the platform boot-on configurations. Signed-off-by: Cristian Marussi --- v2 --> v3 - split from monolithic telemetry protocol patch - swap logic in scmi_telemetry_initial_state_lookup --- drivers/firmware/arm_scmi/telemetry.c | 196 ++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) diff --git a/drivers/firmware/arm_scmi/telemetry.c b/drivers/firmware/arm_s= cmi/telemetry.c index c793ac616a2a..5526447a8a93 100644 --- a/drivers/firmware/arm_scmi/telemetry.c +++ b/drivers/firmware/arm_scmi/telemetry.c @@ -751,6 +751,190 @@ static int iter_de_descr_process_response(const struc= t scmi_protocol_handle *ph, return ret; } =20 +static int scmi_telemetry_config_lookup(struct telemetry_info *ti, + unsigned int grp_id, bool *enabled, + unsigned int *active_update_interval) +{ + const struct scmi_protocol_handle *ph =3D ti->ph; + struct scmi_msg_telemetry_config_get *msg; + struct scmi_msg_resp_telemetry_config_get *resp; + struct scmi_xfer *t; + int ret; + + ret =3D ph->xops->xfer_get_init(ph, TELEMETRY_CONFIG_GET, + sizeof(*msg), sizeof(*resp), &t); + if (ret) + return ret; + + msg =3D t->tx.buf; + msg->grp_id =3D grp_id; + msg->flags =3D grp_id =3D=3D SCMI_TLM_GRP_INVALID ? + TELEMETRY_GET_SELECTOR_ORPHANS : TELEMETRY_GET_SELECTOR_GROUP; + + resp =3D t->rx.buf; + ret =3D ph->xops->do_xfer(ph, t); + if (!ret) { + *enabled =3D resp->control & TELEMETRY_ENABLE; + *active_update_interval =3D + SCMI_TLM_GET_UPDATE_INTERVAL(resp->sampling_rate); + } + + ph->xops->xfer_put(ph, t); + + return 0; +} + +static int scmi_telemetry_group_config_lookup(struct telemetry_info *ti, + struct scmi_telemetry_group *grp) +{ + return scmi_telemetry_config_lookup(ti, grp->info->id, &grp->enabled, + &grp->active_update_interval); +} + +static void iter_enabled_list_prepare_message(void *message, + unsigned int desc_index, + const void *priv) +{ + struct scmi_msg_telemetry_de_enabled_list *msg =3D message; + + msg->index =3D cpu_to_le32(desc_index); + msg->flags =3D 0; +} + +static int iter_enabled_list_update_state(struct scmi_iterator_state *st, + const void *response, void *priv) +{ + const struct scmi_msg_resp_telemetry_de_enabled_list *r =3D response; + + st->num_returned =3D le32_get_bits(r->flags, GENMASK(15, 0)); + st->num_remaining =3D le32_get_bits(r->flags, GENMASK(31, 16)); + + if (st->rx_len < (sizeof(*r) + sizeof(r->entry[0]) * st->num_returned)) + return -EINVAL; + + /* + * total enabled is not declared previously anywhere so we + * assume it's returned+remaining on first call. + */ + if (!st->max_resources) + st->max_resources =3D st->num_returned + st->num_remaining; + + return 0; +} + +static int +iter_enabled_list_process_response(const struct scmi_protocol_handle *ph, + const void *response, + struct scmi_iterator_state *st, void *priv) +{ + const struct scmi_msg_resp_telemetry_de_enabled_list *r =3D response; + const struct scmi_enabled_de_desc *desc; + struct telemetry_info *ti =3D priv; + struct telemetry_de *tde; + u32 de_id; + int ret; + + desc =3D &r->entry[st->loop_idx]; + de_id =3D le32_to_cpu(desc->id); + if (scmi_telemetry_tde_lookup(ti, de_id)) { + dev_err(ph->dev, + "Found INVALID DE with DUPLICATED ID:0x%08X\n", de_id); + return -EINVAL; + } + + tde =3D scmi_telemetry_tde_get(ti, de_id); + if (IS_ERR(tde)) + return PTR_ERR(tde); + + tde->de.info->id =3D de_id; + tde->de.enabled =3D true; + tde->de.tstamp_enabled =3D desc->mode =3D=3D DE_ENABLED_WITH_TSTAMP; + + ret =3D scmi_telemetry_tde_register(ti, tde); + if (ret) { + scmi_telemetry_free_tde_put(ti, tde); + return ret; + } + + dev_dbg(ph->dev, "Registered new ENABLED DE with ID:0x%08X\n", + tde->de.info->id); + + return 0; +} + +static int scmi_telemetry_enumerate_des_enabled_list(struct telemetry_info= *ti) +{ + struct scmi_telemetry_res_info *rinfo =3D ACCESS_PRIVATE(ti, rinfo); + const struct scmi_protocol_handle *ph =3D ti->ph; + struct scmi_iterator_ops ops =3D { + .prepare_message =3D iter_enabled_list_prepare_message, + .update_state =3D iter_enabled_list_update_state, + .process_response =3D iter_enabled_list_process_response, + }; + void *iter; + int ret; + + iter =3D ph->hops->iter_response_init(ph, &ops, 0, + TELEMETRY_DE_ENABLED_LIST, + sizeof(u32) * 2, ti); + if (IS_ERR(iter)) + return PTR_ERR(iter); + + ret =3D ph->hops->iter_response_run(iter); + if (ret) + return ret; + + dev_info(ti->ph->dev, "Found %u enabled DEs.\n", rinfo->num_des); + + return 0; +} + +static int scmi_telemetry_initial_state_lookup(struct telemetry_info *ti) +{ + struct device *dev =3D ti->ph->dev; + int ret; + + ret =3D scmi_telemetry_config_lookup(ti, SCMI_TLM_GRP_INVALID, + &ti->info.enabled, + &ti->info.active_update_interval); + if (ret) + return ret; + + if (!ti->info.enabled) + return 0; + + /* + * When Telemetry is found already enabled on the platform, proceed with + * passive discovery using DE_ENABLED_LIST and TCDF scanning: note that + * this CAN only discover DEs exposed via SHMTIs. + * FastChannel DEs need a proper DE_DESCRIPTION enumeration, while, even + * though incoming Notifications could be used for passive discovery too, + * it would carry a considerable risk of assimilating trash as DEs. + */ + dev_info(dev, + "Telemetry found enabled with update interval %ux10^%d\n", + SCMI_TLM_GET_UPDATE_INTERVAL_SECS(ti->info.active_update_interval), + SCMI_TLM_GET_UPDATE_INTERVAL_EXP(ti->info.active_update_interval)); + /* + * Query enabled DEs list: collect states. It will include DEs from any + * interface. Enabled groups still NOT enumerated. + */ + ret =3D scmi_telemetry_enumerate_des_enabled_list(ti); + if (ret) + dev_warn(dev, FW_BUG "Cannot query enabled DE list. Carry-on.\n"); + + /* Discover DEs on SHMTis: collect states/offsets/values */ + for (int id =3D 0; id < ti->num_shmti; id++) { + ret =3D scmi_telemetry_shmti_scan(ti, id, SCAN_DISCOVERY); + if (ret) + dev_warn(dev, + "Failed discovery-scan of SHMTI ID:%d - ret:%d\n", + id, ret); + } + + return 0; +} + static int scmi_telemetry_de_groups_init(struct device *dev, struct telemetry_info *t= i) { @@ -815,6 +999,9 @@ scmi_telemetry_de_groups_init(struct device *dev, struc= t telemetry_info *ti) } } =20 + for (int i =3D 0; i < ti->info.base.num_groups; i++) + scmi_telemetry_group_config_lookup(ti, &rinfo->grps[i]); + rinfo->num_groups =3D ti->info.base.num_groups; =20 return 0; @@ -2495,6 +2682,11 @@ static int scmi_telemetry_reset(const struct scmi_pr= otocol_handle *ph) struct telemetry_info *ti =3D ph->get_priv(ph); =20 scmi_telemetry_local_resources_reset(ti); + /* Fetch again the states from platform. */ + ret =3D scmi_telemetry_initial_state_lookup(ti); + if (ret) + dev_warn(ph->dev, + FW_BUG "Cannot retrieve initial state after reset.\n"); } =20 ph->xops->xfer_put(ph, t); @@ -2850,6 +3042,10 @@ static int scmi_telemetry_protocol_init(const struct= scmi_protocol_handle *ph) return ret; } =20 + ret =3D scmi_telemetry_initial_state_lookup(ti); + if (ret) + dev_warn(dev, FW_BUG "Cannot retrieve initial state. Carry-on.\n"); + ti->info.base.version =3D ph->version; =20 ret =3D ph->set_priv(ph, ti); --=20 2.53.0