From nobody Thu Apr 2 12:14:38 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id B136B381AE5; Sun, 29 Mar 2026 16:34:43 +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=1774802089; cv=none; b=lfDvC0xLN6Ukdi5hzk4wAiEGN1MdkJg7DxKqIS6z6Xby81HXy+tlkzTdJQrBYjldrlMSuWFBeY5SM2G9+RPdh8XgDdfJLp8TdreW+upEaI4A595vir50LpBDmsVodYYxYdJh1d/tYykHBep2i7TWyfVHaXOc0+PP1ARGqv/Rddc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774802089; c=relaxed/simple; bh=7rL+ZJSCrldyQMwL253L0SyLDE5gxwBW/5SRnXT0RDQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=As6zDUJ/ceGkpjtq99QA2VXJQReikpJzscyVdZzD/akV++t5lwf3tUrMgeSL8bWd3Qv7CB9AYb0Z/C5sOi829KFjg04sEgWBK5vmIBj6zwFq4k0HceLnbxX6v7+g4TVBEMXNjlVbydaarvVUeuKTlcILrk4pSsPwAY5iHRGhDrs= 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=Dc7F/uP8; 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="Dc7F/uP8" 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 64B1E3627; Sun, 29 Mar 2026 09:34:37 -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 7A9D33F915; Sun, 29 Mar 2026 09:34:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1774802083; bh=7rL+ZJSCrldyQMwL253L0SyLDE5gxwBW/5SRnXT0RDQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Dc7F/uP822G5vT7OCcPlFhKdC3ydhQ2W8zmSfauBVVczp7NY4a1T3NiVaQ8I32sVX VDFdN2MX/rqFgpwZa6gwI/cP2WGj83bj7ATIXInBx7JfmknKOXtEZjwNxSgVmaFuGR yFmmSC2fl+/ikSzhApdgfWBTz/w8u4efnFxXfkwM= 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 09/24] firmware: arm_scmi: Add support to parse SHMTIs areas Date: Sun, 29 Mar 2026 17:33:20 +0100 Message-ID: <20260329163337.637393-10-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 logic to scan the SHMTI areas, parsing the TDCF descriptors while collecting DataEvent, BlockTimestamp and UUID lines. Signed-off-by: Cristian Marussi --- v2 --> v3 - split from monolithic Telemetry patch - avoid devres allocation for resources that are added to the xa_lines XAr= ray - simplify prototype of line parsing helpers to drop unneeded dev - flip tstmap logic in scmi_telemetry_line_data_parse() to properly emit a TLM ftrace event - use ternary ops to simplify quite a few expressions --- drivers/firmware/arm_scmi/telemetry.c | 576 ++++++++++++++++++++++++++ 1 file changed, 576 insertions(+) diff --git a/drivers/firmware/arm_scmi/telemetry.c b/drivers/firmware/arm_s= cmi/telemetry.c index 7e5af7bd9fdc..6c5a988b2aac 100644 --- a/drivers/firmware/arm_scmi/telemetry.c +++ b/drivers/firmware/arm_scmi/telemetry.c @@ -254,6 +254,23 @@ struct uuid_line { u32 dwords[SCMI_TLM_DE_IMPL_MAX_DWORDS]; }; =20 +#define LINE_DATA_GET(f) \ +({ \ + typeof(f) _f =3D (f); \ + \ + (TO_CPU_64(_I(&_f->data_high), _I(&_f->data_low))); \ +}) + +#define LINE_TSTAMP_GET(f) \ +({ \ + typeof(f) _f =3D (f); \ + \ + (TO_CPU_64(_I(&_f->ts_high), _I(&_f->ts_low))); \ +}) + +#define BLK_TS_STAMP(f) LINE_TSTAMP_GET(f) +#define BLK_TS_RATE(p) PAYLD_ID(p) + enum tdcf_line_types { TDCF_DATA_LINE, TDCF_BLK_TS_LINE, @@ -365,6 +382,7 @@ struct telemetry_line { refcount_t users; u32 last_magic; struct payload __iomem *payld; + struct xarray *xa_lines; /* Protect line accesses */ struct mutex mtx; }; @@ -424,6 +442,7 @@ struct telemetry_info { struct telemetry_de *tdes; struct scmi_telemetry_group *grps; struct xarray xa_des; + struct xarray xa_lines; /* Mutex to protect access to @free_des */ struct mutex free_mtx; struct list_head free_des; @@ -1119,6 +1138,555 @@ scmi_telemetry_resources_get(const struct scmi_prot= ocol_handle *ph) return ti->res_get(ti); } =20 +static u64 +scmi_telemetry_blkts_read(u32 magic, struct telemetry_block_ts *bts) +{ + if (WARN_ON(!bts || !refcount_read(&bts->line.users))) + return 0; + + guard(mutex)(&bts->line.mtx); + + if (bts->line.last_magic =3D=3D magic) + return bts->last_ts; + + /* Note that the bts->last_rate can change ONLY on creation */ + bts->last_ts =3D BLK_TS_STAMP(&bts->line.payld->blk_tsl); + bts->line.last_magic =3D magic; + + return bts->last_ts; +} + +static void scmi_telemetry_blkts_update(struct telemetry_info *ti, u32 mag= ic, + struct telemetry_block_ts *bts) +{ + guard(mutex)(&bts->line.mtx); + + if (bts->line.last_magic !=3D magic) { + bts->last_ts =3D BLK_TS_STAMP(&bts->line.payld->blk_tsl); + bts->last_rate =3D BLK_TS_RATE(bts->line.payld); + /* BLK_TS clock rate value can change ONLY here on creation */ + if (!bts->last_rate) + bts->last_rate =3D ti->default_blk_ts_rate; + bts->line.last_magic =3D magic; + } +} + +static void scmi_telemetry_line_put(struct telemetry_line *line, void *blo= b) +{ + if (refcount_dec_and_test(&line->users)) { + scoped_guard(mutex, &line->mtx) + xa_erase(line->xa_lines, (unsigned long)line->payld); + kfree(blob); + } +} + +static void scmi_telemetry_blkts_unlink(struct telemetry_de *tde) +{ + scmi_telemetry_line_put(&tde->bts->line, tde->bts); + tde->bts =3D NULL; +} + +static void scmi_telemetry_uuid_unlink(struct telemetry_de *tde) +{ + scmi_telemetry_line_put(&tde->uuid->line, tde->uuid); + tde->uuid =3D NULL; +} + +static void scmi_telemetry_de_unlink(struct scmi_telemetry_de *de) +{ + struct telemetry_de *tde =3D to_tde(de); + + /* Unlink all related lines triggering their deallocation */ + if (tde->bts) + scmi_telemetry_blkts_unlink(tde); + if (tde->uuid) + scmi_telemetry_uuid_unlink(tde); +} + +static struct telemetry_line * +scmi_telemetry_line_get(struct xarray *xa_lines, struct payload *payld) +{ + struct telemetry_line *line; + + line =3D xa_load(xa_lines, (unsigned long)payld); + if (!line) + return NULL; + + refcount_inc(&line->users); + + return line; +} + +static int +scmi_telemetry_line_init(struct telemetry_line *line, struct xarray *xa_li= nes, + struct payload __iomem *payld) +{ + refcount_set(&line->users, 1); + line->payld =3D payld; + line->xa_lines =3D xa_lines; + mutex_init(&line->mtx); + + return xa_insert(xa_lines, (unsigned long)payld, line, GFP_KERNEL); +} + +static struct telemetry_block_ts * +scmi_telemetry_blkts_create(struct device *dev, struct xarray *xa_lines, + struct payload *payld) +{ + struct telemetry_block_ts *bts; + int ret; + + bts =3D kzalloc(sizeof(*bts), GFP_KERNEL); + if (!bts) + return NULL; + + ret =3D scmi_telemetry_line_init(&bts->line, xa_lines, payld); + if (ret) { + kfree(bts); + return NULL; + } + + trace_scmi_tlm_collect(0, (u64)payld, 0, "SHMTI_NEW_BLKTS"); + + return bts; +} + +static struct telemetry_block_ts * +scmi_telemetry_blkts_get_or_create(struct device *dev, struct xarray *xa_l= ines, + struct payload *payld) +{ + struct telemetry_line *line; + + line =3D scmi_telemetry_line_get(xa_lines, payld); + if (line) + return to_blkts(line); + + return scmi_telemetry_blkts_create(dev, xa_lines, payld); +} + +static struct telemetry_uuid * +scmi_telemetry_uuid_create(struct device *dev, struct xarray *xa_lines, + struct payload *payld) +{ + struct telemetry_uuid *uuid; + int ret; + + uuid =3D kzalloc(sizeof(*uuid), GFP_KERNEL); + if (!uuid) + return NULL; + + for (int i =3D 0; i < SCMI_TLM_DE_IMPL_MAX_DWORDS; i++) + uuid->de_impl_version[i] =3D le32_to_cpu(payld->uuid_l.dwords[i]); + + ret =3D scmi_telemetry_line_init(&uuid->line, xa_lines, payld); + if (ret) { + kfree(uuid); + return NULL; + } + + trace_scmi_tlm_collect(0, (u64)payld, 0, "SHMTI_NEW_UUID"); + + return uuid; +} + +static struct telemetry_uuid * +scmi_telemetry_uuid_get_or_create(struct device *dev, struct xarray *xa_li= nes, + struct payload *payld) +{ + struct telemetry_line *line; + + line =3D scmi_telemetry_line_get(xa_lines, payld); + if (line) + return to_uuid(line); + + return scmi_telemetry_uuid_create(dev, xa_lines, payld); +} + +static void scmi_telemetry_tdcf_uuid_parse(struct telemetry_info *ti, + struct payload __iomem *payld, + struct telemetry_shmti *shmti, + void **active_uuid) +{ + struct telemetry_uuid *uuid; + + if (UUID_INVALID(payld)) { + trace_scmi_tlm_access(0, "UUID_INVALID", 0, 0); + return; + } + + /* A UUID descriptor MUST be returned: it is found or it is created */ + uuid =3D scmi_telemetry_uuid_get_or_create(ti->ph->dev, &ti->xa_lines, + payld); + if (WARN_ON(!uuid)) + return; + + *active_uuid =3D uuid; +} + +static struct payload * +scmi_telemetry_nearest_line_by_type(struct telemetry_shmti *shmti, + void *last, enum tdcf_line_types ltype) +{ + struct tdcf __iomem *tdcf =3D shmti->base; + void *next, *found =3D NULL; + + /* Scan from start of TDCF payloads up to last_payld */ + next =3D tdcf->payld; + while (next < last) { + if (LINE_TYPE((struct payload *)next) =3D=3D ltype) + found =3D next; + + next +=3D LINE_LENGTH_WORDS((struct payload *)next); + } + + return found; +} + +static struct telemetry_block_ts * +scmi_telemetry_blkts_bind(struct device *dev, struct telemetry_shmti *shmt= i, + struct payload *payld, struct xarray *xa_lines, + struct payload *bts_payld) +{ + /* Trigger a manual search when no BLK_TS payload offset was provided */ + if (!bts_payld) { + /* Find the BLK_TS immediately preceding this DE payld */ + bts_payld =3D scmi_telemetry_nearest_line_by_type(shmti, payld, + TDCF_BLK_TS_LINE); + if (!bts_payld) + return NULL; + } + + return scmi_telemetry_blkts_get_or_create(dev, xa_lines, bts_payld); +} + +/** + * scmi_telemetry_tdcf_blkts_parse - A BLK_TS line parser + * + * @ti: A reference to the telemetry_info descriptor + * @payld: TDCF payld line to process + * @shmti: SHMTI descriptor inside which the scan is happening + * @active_bts: Input/output reference to keep track of the last blk_ts fo= und + * + * Process a valid TDCF BLK_TS line and, after having looked up or created= a + * blk_ts descriptor, update the related data and return it as the current= ly + * active blk_ts, given that it is effectively the last found during this + * scan. + */ +static void scmi_telemetry_tdcf_blkts_parse(struct telemetry_info *ti, + struct payload __iomem *payld, + struct telemetry_shmti *shmti, + void **active_bts) +{ + struct telemetry_block_ts *bts; + + /* Check for spec compliance */ + if (BLK_TS_INVALID(payld)) { + trace_scmi_tlm_access(0, "BLK_TS_INVALID", 0, 0); + return; + } + + /* A BLK_TS descriptor MUST be returned: it is found or it is created */ + bts =3D scmi_telemetry_blkts_get_or_create(ti->ph->dev, + &ti->xa_lines, payld); + if (WARN_ON(!bts)) + return; + + /* Update the descriptor with the lastest TS */ + scmi_telemetry_blkts_update(ti, shmti->last_magic, bts); + *active_bts =3D bts; +} + +static inline struct telemetry_de * +scmi_telemetry_tde_allocate(struct telemetry_info *ti, u32 de_id, + struct payload __iomem *payld) +{ + struct telemetry_de *tde; + + tde =3D scmi_telemetry_tde_get(ti, de_id); + if (IS_ERR(tde)) + return NULL; + + tde->de.info->id =3D de_id; + tde->de.enabled =3D true; + tde->de.tstamp_enabled =3D LINE_TS_VALID(payld) || USE_BLK_TS(payld); + + if (scmi_telemetry_tde_register(ti, tde)) { + scmi_telemetry_free_tde_put(ti, tde); + return NULL; + } + + return tde; +} + +static inline void +scmi_telemetry_line_data_parse(struct telemetry_de *tde, u64 *val, u64 *ts= tamp, + struct payload __iomem *payld, u32 magic) +{ + /* Data is always valid since we are NOT handling BLK TS lines here */ + *val =3D LINE_DATA_GET(&payld->l); + if (tstamp) { + if (USE_BLK_TS(payld)) { + /* Read out the actual BLK_TS */ + *tstamp =3D scmi_telemetry_blkts_read(magic, tde->bts); + } else if (LINE_TS_VALID(payld)) { + /* + * Note that LINE_TS_VALID implies HAS_LINE_EXT and that + * the per DE line_ts_rate is advertised in the DE + * descriptor. + */ + *tstamp =3D LINE_TSTAMP_GET(&payld->tsl); + } else { + *tstamp =3D 0; + } + } + + trace_scmi_tlm_collect(tstamp ? *tstamp : 0, tde->de.info->id, + *val, "SHMTI_DE_READ"); +} + +static inline void scmi_telemetry_bts_link(struct telemetry_de *tde, + struct telemetry_block_ts *bts) +{ + refcount_inc(&bts->line.users); + tde->bts =3D bts; + /* Update TS clock rate if provided by the BLK_TS */ + if (tde->bts->last_rate) + tde->de.info->ts_rate =3D tde->bts->last_rate; +} + +static inline void scmi_telemetry_uuid_link(struct telemetry_de *tde, + struct telemetry_uuid *uuid) +{ + refcount_inc(&uuid->line.users); + tde->uuid =3D uuid; +} + +/** + * scmi_telemetry_tdcf_data_parse - TDCF DataLine parsing + * @ti: A reference to the telemetry info descriptor + * @payld: Line payload to parse + * @shmti: A reference to the containing SHMTI area + * @mode: A flag to determine the behaviour of the scan + * @active_bts: A pointer to keep track and report any found BLK timestamp= line + * @active_uuid: A pointer to keep track and report any found UUID line + * + * This routine takes care to: + * - verify line consistency in relation to the used flags and the current + * context: e.g. is there an active preceding BLK_TS line if the DataLi= ne + * sports a USE_BLKTS flag ? + * - verify the related Data Event ID exists OR create a brand new DE + * (depending on the @mode of operation) + * - links any active BLK_TS or UUID line to the current DE + * - read and save value/tstamp for the DE ONLY if anything has changed (= by + * tracking the last TDCF magic) and update related magic: this allows = to + * minimize future needs of single-DE reads + * + * Modes of operation. + * + * The scan behaviour depends on the chosen @mode: + * - SCAN_LOOKUP: the basic scan which aims to update value associated = to + * existing DEs. Any discovered DataLine that could NOT be + * matched to an existing, previously discovered, DE is + * discarded. This is the normal scan behaviour. + * - SCAN_UPDATE: a more advanced scan which provides all the SCAN_LOOK= UP + * features plus takes care to update the DEs location + * coordinates inside the SHMTI: note that the related DEs are + * still supposed to have been previously discovered when + * this scan runs. This is used to update location + * coordinates for DEs contained in a Group when such group + * is enabled. + * - SCAN_DISCOVERY: the most advanced scan available which provides all + * the SCAN_LOOKUP features plus discovery capabilities: + * any DataLine referring to a previously unknown DE leads + * to the allocation of a new DE descriptor. + * This mode is used on the first scan at init time, ONLY + * if Telemetry was found to be already enabled at boot on + * the platform side: this helps to maximize gathered + * information when dealing with out of spec firmwares. + * Any usage of this discovery mode other than in a boot-on + * enabled scenario is discouraged since it can easily + * lead to spurious DE discoveries. + */ +static void scmi_telemetry_tdcf_data_parse(struct telemetry_info *ti, + struct payload __iomem *payld, + struct telemetry_shmti *shmti, + enum scan_mode mode, + void *active_bts, void *active_uuid) +{ + bool use_blk_ts =3D USE_BLK_TS(payld); + struct telemetry_de *tde; + u64 val, tstamp =3D 0; + u32 de_id; + + de_id =3D PAYLD_ID(payld); + /* Discard malformed lines...a preceding BLK_TS must exist */ + if (use_blk_ts && !active_bts) { + trace_scmi_tlm_access(de_id, "BAD_USE_BLK_TS", 0, 0); + return; + } + + /* Is this DE ID known ? */ + tde =3D scmi_telemetry_tde_lookup(ti, de_id); + if (!tde) { + if (mode !=3D SCAN_DISCOVERY) { + trace_scmi_tlm_access(de_id, "DE_INVALID", 0, 0); + return; + } + + /* In SCAN_DISCOVERY mode we allocate new DEs for unknown IDs */ + tde =3D scmi_telemetry_tde_allocate(ti, de_id, payld); + if (!tde) + return; + } + + /* Update DE location refs if requested: normally done only on enable */ + if (mode >=3D SCAN_UPDATE) { + tde->base =3D shmti->base; + tde->eplg =3D SHMTI_EPLG(shmti); + tde->offset =3D (void *)payld - (void *)shmti->base; + + dev_dbg(ti->ph->dev, + "TDCF-updated DE_ID:0x%08X - shmti:%pK offset:%u\n", + tde->de.info->id, tde->base, tde->offset); + } + + /* Has any value/tstamp really changed ?*/ + scoped_guard(mutex, &tde->mtx) { + if (tde->last_magic =3D=3D shmti->last_magic) + return; + } + + /* Link the related BTS when needed, it's unlinked on disable */ + if (use_blk_ts && !tde->bts) + scmi_telemetry_bts_link(tde, active_bts); + + /* Link the active UUID when existent, it's unlinked on disable */ + if (active_uuid) + scmi_telemetry_uuid_link(tde, active_uuid); + + /* Parse data words */ + scmi_telemetry_line_data_parse(tde, &val, &tstamp, payld, + shmti->last_magic); + + guard(mutex)(&tde->mtx); + tde->last_magic =3D shmti->last_magic; + tde->last_val =3D val; + tde->last_ts =3D tde->de.tstamp_enabled ? tstamp : 0; +} + +static int scmi_telemetry_tdcf_line_parse(struct telemetry_info *ti, + struct payload __iomem *payld, + struct telemetry_shmti *shmti, + enum scan_mode mode, + void **active_bts, void **active_uuid) +{ + int used_qwords; + + used_qwords =3D LINE_LENGTH_QWORDS(payld); + /* Invalid lines are not an error, could simply be disabled DEs */ + if (DATA_INVALID(payld)) { + trace_scmi_tlm_access(PAYLD_ID(payld), "TDCF_INVALID", 0, 0); + return used_qwords; + } + + switch (LINE_TYPE(payld)) { + case TDCF_DATA_LINE: + scmi_telemetry_tdcf_data_parse(ti, payld, shmti, mode, + *active_bts, *active_uuid); + break; + case TDCF_BLK_TS_LINE: + scmi_telemetry_tdcf_blkts_parse(ti, payld, shmti, active_bts); + break; + case TDCF_UUID_LINE: + scmi_telemetry_tdcf_uuid_parse(ti, payld, shmti, active_uuid); + break; + default: + trace_scmi_tlm_access(PAYLD_ID(payld), "TDCF_UNKNOWN", 0, 0); + break; + } + + return used_qwords; +} + +/** + * scmi_telemetry_shmti_scan - Full SHMTI scan + * @ti: A reference to the telemetry info descriptor + * @shmti_id: ID of the SHMTI area that has to be scanned + * @mode: A flag to determine the behaviour of the scan + * + * Return: 0 on Success + */ +static int scmi_telemetry_shmti_scan(struct telemetry_info *ti, + unsigned int shmti_id, enum scan_mode mode) +{ + struct telemetry_shmti *shmti =3D &ti->shmti[shmti_id]; + struct tdcf __iomem *tdcf =3D shmti->base; + int retries =3D SCMI_TLM_TDCF_MAX_RETRIES; + u32 startm =3D 0, endm =3D TDCF_BAD_END_SEQ; + + if (!tdcf) + return -ENODEV; + + do { + void *active_bts =3D NULL, *active_uuid =3D NULL; + unsigned int qwords; + void __iomem *next; + + /* A bit of exponential backoff between retries */ + fsleep((SCMI_TLM_TDCF_MAX_RETRIES - retries) * 1000); + + /* + * Note that during a full SHMTI scan the magic seq numbers are + * checked only at the start and at the end of the scan, NOT + * between each parsed line and this has these consequences: + * - TDCF magic numbers accesses are reduced to 2 reads + * - the set of values obtained from a full scan belong all + * to the same platform update (same magic number) + * - a SHMTI full scan is an all or nothing operation: when + * a potentially corrupted read is detected along the way + * (MSEQ_MISMATCH) another full scan is triggered. + */ + startm =3D TDCF_START_SEQ_GET(tdcf); + if (IS_BAD_START_SEQ(startm)) { + trace_scmi_tlm_access(0, "MSEQ_BADSTART", startm, 0); + continue; + } + + /* On a BAD_SEQ this will be updated on the next attempt */ + shmti->last_magic =3D startm; + + qwords =3D QWORDS(tdcf); + next =3D tdcf->payld; + while (qwords) { + int used_qwords; + + used_qwords =3D scmi_telemetry_tdcf_line_parse(ti, next, + shmti, mode, + &active_bts, + &active_uuid); + if (qwords < used_qwords) { + trace_scmi_tlm_access(PAYLD_ID(next), + "BAD_QWORDS", startm, 0); + return -EINVAL; + } + + next +=3D used_qwords * 8; + qwords -=3D used_qwords; + } + + endm =3D TDCF_END_SEQ_GET(SHMTI_EPLG(shmti)); + if (startm !=3D endm) + trace_scmi_tlm_access(0, "MSEQ_MISMATCH", startm, endm); + } while (startm !=3D endm && --retries); + + if (startm !=3D endm) { + trace_scmi_tlm_access(0, "TDCF_SCAN_FAIL", startm, endm); + return -EPROTO; + } + + return 0; +} + static const struct scmi_telemetry_proto_ops tlm_proto_ops =3D { .info_get =3D scmi_telemetry_info_get, .de_lookup =3D scmi_telemetry_de_lookup, @@ -1208,6 +1776,13 @@ static void scmi_telemetry_resources_free(void *arg) struct telemetry_info *ti =3D arg; struct scmi_telemetry_res_info *rinfo =3D ACCESS_PRIVATE(ti, rinfo); =20 + /* + * Unlinking all the BLK_TS/UUID lines related to a DE triggers also + * the deallocation of such lines when the embedded refcount hits zero. + */ + for (int i =3D 0; i < rinfo->num_des; i++) + scmi_telemetry_de_unlink(rinfo->des[i]); + kfree(ti->tdes); kfree(rinfo->des); kfree(rinfo->dei_store); @@ -1313,6 +1888,7 @@ static int scmi_telemetry_instance_init(struct teleme= try_info *ti) return ret; =20 xa_init(&ti->xa_des); + xa_init(&ti->xa_lines); /* Setup resources lazy initialization */ atomic_set(&ti->rinfo_initializing, 0); init_completion(&ti->rinfo_initdone); --=20 2.53.0