From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1968E36A01A for ; Thu, 21 May 2026 04:39:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779338358; cv=none; b=GNUFB+h4TqrQ6lNbu/fOLN6pz5Rt9Gjfav8jmnyJLIpfhUPl/mqICvK6tF/hgq15CyNTWKf0wsBz8XwfZzJDz87BjiRZko4unXiEAcSFcbcryU23FOBiYcvp5jgKtA/cAUoH1D7jdrlthsS7CDV5h5LXWl9cG86Er/CKX7LO+2Q= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779338358; c=relaxed/simple; bh=5srjwpp6Hk4LiRfO82SCH0YRXb4BGZ0/SJ9tNjbbhOQ=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=JyTdcB4pquct5mQ9SlDKsURmbvOnLCZWJ8APKqMrcJw2a3TgBkwdbNL05k3Nw1i9IxBL1912RMa242Vlyi8rAhRMdjDNKRgorYk6yZvNnhzI/hapvKZruObjXADDBAJCm6M8WThdNUPgtYOmHHj9WDg8KNvMMtsqS/CCK727hZk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Z+c0nDI/; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Z+c0nDI/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779338354; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ggCKS8QEvnLR4SsIv3hBNn6nRmerd7pd3z3ZeYISTIg=; b=Z+c0nDI//LowMwh2QMZH31ji/wiCNookSqywTG9gL8ILFitwntEyqhV+XVEe2jyvcl9Kni eHgMQcgQsO3YhESWnYhekrgwMUI485j+R1o6O++puWRDg77M4oyEGqXMvNnmmoTtETnPkt DcCJsDbqF8a6AHou7XeySd4qALvOEnA= Received: from mail-pg1-f200.google.com (mail-pg1-f200.google.com [209.85.215.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-608-0skjvf3yNLeux-zaZu1o7g-1; Thu, 21 May 2026 00:39:12 -0400 X-MC-Unique: 0skjvf3yNLeux-zaZu1o7g-1 X-Mimecast-MFC-AGG-ID: 0skjvf3yNLeux-zaZu1o7g_1779338352 Received: by mail-pg1-f200.google.com with SMTP id 41be03b00d2f7-c82c935e048so4007886a12.0 for ; Wed, 20 May 2026 21:39:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779338351; x=1779943151; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=ggCKS8QEvnLR4SsIv3hBNn6nRmerd7pd3z3ZeYISTIg=; b=ZuyO+TfXKBjLPVxepD/b7VNbvkCJlee1OR105VAcT3TK5uJgIdNm6M3o4pMPjAzioE 5X2aaAnG9fQcbtud7DWN4OGevvGS3msZGDGTO4Zmj/mXhBQwaDDi1O4L9yq/7vecNsy8 O/ZicKCS2X/wWv+jp8pgaKj3Timuv+AT+jAeYkEz7nFrEAPGI+ZJt7WvcbRfe+jb4vvN diWrdafUIlrnOuTOeJA37myvQN91j+dOtBU4ZSd5TCFyL+9fzdqRy/QAl+YGPgXjWald kShbPJ4B29Sg8EjRk5AFtcq6wXinInJCcZvNjVGp6Ou1SZPDdQLeGdo2klwSRSyP0MGC hgwg== X-Forwarded-Encrypted: i=1; AFNElJ+7xt5HBA+dJqJe/EJsj+jmEFuJtJZStoYILXA71H3lTl/aTweguOWKJyp7hv0DWV8Shie7xIgkzw65@lists.linux.dev X-Gm-Message-State: AOJu0YwLW5nP1Ge+NtoAAgj5PXWFUmeKv/dtAgQDLn16QpBnLmueQfJM 2QNH9CBdkXbAnceohgUH26IjOObAoVaAE0KRfrL9e1z0ZfZxHizXmnt3LZxm8Marj6lP1E4Ah8s hZPdnp5I7Jvo+5LIJ1OykRMY0rpuxMQ/7T7v711lHoLeGUcxck/wmCZpBjzmJwt8= X-Gm-Gg: Acq92OG6/LUGchnFfRh7bzq0evtiRFR+/Ey0QUlKcxOKRAexTdSMbo/L1AQrxyMwPkN EAJ1RkEY3uyyM038Bv/QpLvz53KJ33o1Rn0g5YI67GjyaAjUvVmARN5TpTtGLVkEf2butmJk/yE y9ykCjjmXyAC34cidlR5nq77bg8Al2ZWshUdtEWqGkJMHSDvnuemhaiNYp7AwpBQKpPAEwkzAX3 WG0jmPapsf3WbqqpBFOZfMQHCU+eTF287MW475vxFr/kNxwG0fsokwHaobKTK0sz1CgabQKlbg3 mGFY/l/yQwFEXZYOTjzARLQLx9ID1AqrxpsMdfZGFTPgdyiQvd1KImRA6Pw/mkHh+PxDcIEeuJx Nr2RWx4uc+jVH2LL2AWn7J95pHt2TlJsnTGkd5wzymZImjRLdp69zYaD3j8qRrSYr X-Received: by 2002:a05:6a20:4305:b0:3a3:171f:6afb with SMTP id adf61e73a8af0-3b307bdf25amr1353963637.4.1779338351420; Wed, 20 May 2026 21:39:11 -0700 (PDT) X-Received: by 2002:a05:6a20:4305:b0:3a3:171f:6afb with SMTP id adf61e73a8af0-3b307bdf25amr1353913637.4.1779338350895; Wed, 20 May 2026 21:39:10 -0700 (PDT) Received: from [192.168.68.51] (n175-34-8-244.mrk21.qld.optusnet.com.au. [175.34.8.244]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c82c4031662sm20535429a12.16.2026.05.20.21.39.01 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 20 May 2026 21:39:10 -0700 (PDT) Message-ID: <872ce762-0a83-42a4-bbe8-b21ea6f4e1cf@redhat.com> Date: Thu, 21 May 2026 14:38:59 +1000 Precedence: bulk X-Mailing-List: linux-coco@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v14 10/44] arm64: RMI: Add support for SRO To: Steven Price , kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo.Pieralisi2@arm.com References: <20260513131757.116630-1-steven.price@arm.com> <20260513131757.116630-11-steven.price@arm.com> From: Gavin Shan In-Reply-To: <20260513131757.116630-11-steven.price@arm.com> X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: QS_mBDPKlx7G4UNuTgnq6PjLmIZOMDnNIrhSFkMSylk_1779338352 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Hi Steven, On 5/13/26 11:17 PM, Steven Price wrote: > RMM v2.0 introduces the concept of "Stateful RMI Operations" (SRO). This > means that an SMC can return with an operation still in progress. The > host is excepted to continue the operation until is reaches a conclusion > (either success or failure). During this process the RMM can request > additional memory ('donate') or hand memory back to the host > ('reclaim'). The host can request an in progress operation is cancelled, > but still continue the operation until it has completed (otherwise the > incomplete operation may cause future RMM operations to fail). > > The SRO is tracked using a struct rmi_sro_state object which keeps track > of any memory which has been allocated but not yet consumed by the RMM > or reclaimed from the RMM. This allows the memory to be reused in a > future request within the same operation. It will also permit an > operation to be done in a context where memory allocation may be > difficult (e.g. atomic context) with the option to abort the operation > and retry the memory allocation outside of the atomic context. The > memory stored in the struct rmi_sro_state object can then be reused on > the subsequent attempt. > > Signed-off-by: Steven Price > --- > v14: > * SRO support has improved although is still not fully complete. The > infrastructure has been moved out of KVM. > --- > arch/arm64/include/asm/rmi_cmds.h | 1 + > arch/arm64/kernel/rmi.c | 359 ++++++++++++++++++++++++++++++ > 2 files changed, 360 insertions(+) > > diff --git a/arch/arm64/include/asm/rmi_cmds.h b/arch/arm64/include/asm/rmi_cmds.h > index eb213c8e6f26..1a7b0c8f1e38 100644 > --- a/arch/arm64/include/asm/rmi_cmds.h > +++ b/arch/arm64/include/asm/rmi_cmds.h > @@ -35,6 +35,7 @@ struct rmi_sro_state { > > int rmi_delegate_range(phys_addr_t phys, unsigned long size); > int rmi_undelegate_range(phys_addr_t phys, unsigned long size); > +int free_delegated_page(phys_addr_t phys); > > static inline int rmi_delegate_page(phys_addr_t phys) > { > diff --git a/arch/arm64/kernel/rmi.c b/arch/arm64/kernel/rmi.c > index 08cef54acadb..a8107ca9bb6d 100644 > --- a/arch/arm64/kernel/rmi.c > +++ b/arch/arm64/kernel/rmi.c > @@ -48,6 +48,365 @@ int rmi_undelegate_range(phys_addr_t phys, unsigned long size) > return ret; > } > > +static unsigned long donate_req_to_size(unsigned long donatereq) > +{ > + unsigned long unit_size = RMI_DONATE_SIZE(donatereq); > + > + switch (unit_size) { > + case 0: > + return PAGE_SIZE; > + case 1: > + return PMD_SIZE; > + case 2: > + return PUD_SIZE; > + case 3: > + return P4D_SIZE; > + } > + unreachable(); > +} > + It's worthy to have 'inline'. {P4D, PUD, PMD}_SIZE can be equal if there are no P4D and PUD, depending on CONFIG_PGTABLE_LEVELS. In this case, can the 'unit_size' be translated to wrong value? > +static void rmi_smccc_invoke(struct arm_smccc_1_2_regs *regs_in, > + struct arm_smccc_1_2_regs *regs_out) > +{ > + struct arm_smccc_1_2_regs regs = *regs_in; > + unsigned long status; > + > + do { > + arm_smccc_1_2_invoke(®s, regs_out); > + status = RMI_RETURN_STATUS(regs_out->a0); > + } while (status == RMI_BUSY || status == RMI_BLOCKED); > +} > + > +int free_delegated_page(phys_addr_t phys) > +{ > + if (WARN_ON(rmi_undelegate_page(phys))) { > + /* Undelegate failed: leak the page */ > + return -EBUSY; > + } > + > + free_page((unsigned long)phys_to_virt(phys)); > + > + return 0; > +} > + > +static int rmi_sro_ensure_capacity(struct rmi_sro_state *sro, > + unsigned long count) > +{ > + if (WARN_ON_ONCE(sro->addr_count > RMI_MAX_ADDR_LIST)) > + return -EOVERFLOW; > + > + if (count > RMI_MAX_ADDR_LIST - sro->addr_count) > + return -ENOSPC; > + > + return 0; > +} > + > +static int rmi_sro_donate_contig(struct rmi_sro_state *sro, > + unsigned long sro_handle, > + unsigned long donatereq, > + struct arm_smccc_1_2_regs *out_regs, > + gfp_t gfp) > +{ > + unsigned long unit_size = RMI_DONATE_SIZE(donatereq); > + unsigned long unit_size_bytes = donate_req_to_size(donatereq); > + unsigned long count = RMI_DONATE_COUNT(donatereq); > + unsigned long state = RMI_DONATE_STATE(donatereq); > + unsigned long size = unit_size_bytes * count; > + unsigned long addr_range; > + int ret; > + void *virt; > + phys_addr_t phys; > + struct arm_smccc_1_2_regs regs = { > + SMC_RMI_OP_MEM_DONATE, > + sro_handle > + }; > + > + for (int i = 0; i < sro->addr_count; i++) { > + unsigned long entry = sro->addr_list[i]; > + > + if (RMI_ADDR_RANGE_SIZE(entry) == unit_size && > + RMI_ADDR_RANGE_COUNT(entry) == count && > + RMI_ADDR_RANGE_STATE(entry) == state) { > + sro->addr_count--; > + swap(sro->addr_list[sro->addr_count], > + sro->addr_list[i]); > + > + goto out; > + } > + } > + > + ret = rmi_sro_ensure_capacity(sro, 1); > + if (ret) > + return ret; > + > + virt = alloc_pages_exact(size, gfp); > + if (!virt) > + return -ENOMEM; > + phys = virt_to_phys(virt); > + alloc_pages_exact() will fail if the requested size exceeds the maximal allowed size (1 << MAX_PAGE_ORDER). The maximal size is usually smaller than PUD_SIZE but PUD_SIZE is allowed by the RMM. > + if (state == RMI_OP_MEM_DELEGATED) { > + if (rmi_delegate_range(phys, size)) { > + free_pages_exact(virt, size); > + return -ENXIO; > + } > + } > + > + addr_range = phys & RMI_ADDR_RANGE_ADDR_MASK; > + FIELD_MODIFY(RMI_ADDR_RANGE_SIZE_MASK, &addr_range, unit_size); > + FIELD_MODIFY(RMI_ADDR_RANGE_COUNT_MASK, &addr_range, count); > + FIELD_MODIFY(RMI_ADDR_RANGE_STATE_MASK, &addr_range, state); > + > + sro->addr_list[sro->addr_count] = addr_range; > + > +out: > + regs.a2 = virt_to_phys(&sro->addr_list[sro->addr_count]); > + regs.a3 = 1; > + rmi_smccc_invoke(®s, out_regs); > + > + unsigned long donated_granules = out_regs->a1; > + unsigned long donated_size = donated_granules << PAGE_SHIFT; > + > + if (donated_granules == 0) { > + /* No pages used by the RMM */ > + sro->addr_count++; > + } else if (donated_size < size) { > + phys = sro->addr_list[sro->addr_count] & RMI_ADDR_RANGE_ADDR_MASK; > + > + /* Not all granules used by the RMM, free the remaining pages */ > + for (long i = donated_size; i < size; i += PAGE_SIZE) { > + if (state == RMI_OP_MEM_DELEGATED) > + free_delegated_page(phys + i); > + else > + __free_page(phys_to_page(phys + i)); > + } > + } > + > + return 0; > +} > + > +static int rmi_sro_donate_noncontig(struct rmi_sro_state *sro, > + unsigned long sro_handle, > + unsigned long donatereq, > + struct arm_smccc_1_2_regs *out_regs, > + gfp_t gfp) > +{ > + unsigned long unit_size = RMI_DONATE_SIZE(donatereq); > + unsigned long unit_size_bytes = donate_req_to_size(donatereq); > + unsigned long count = RMI_DONATE_COUNT(donatereq); > + unsigned long state = RMI_DONATE_STATE(donatereq); > + unsigned long found = 0; > + unsigned long addr_list_start = sro->addr_count; > + int ret; > + struct arm_smccc_1_2_regs regs = { > + SMC_RMI_OP_MEM_DONATE, > + sro_handle > + }; > + > + for (int i = 0; i < addr_list_start && found < count; i++) { > + unsigned long entry = sro->addr_list[i]; > + > + if (RMI_ADDR_RANGE_SIZE(entry) == unit_size && > + RMI_ADDR_RANGE_COUNT(entry) == 1 && > + RMI_ADDR_RANGE_STATE(entry) == state) { > + addr_list_start--; > + swap(sro->addr_list[addr_list_start], > + sro->addr_list[i]); > + found++; > + i--; > + } > + } > + > + ret = rmi_sro_ensure_capacity(sro, count - found); > + if (ret) > + return ret; > + > + while (found < count) { > + unsigned long addr_range; > + void *virt = alloc_pages_exact(unit_size_bytes, gfp); > + phys_addr_t phys; > + > + if (!virt) > + return -ENOMEM; > + > + phys = virt_to_phys(virt); > + > + if (state == RMI_OP_MEM_DELEGATED) { > + if (rmi_delegate_range(phys, unit_size_bytes)) { > + free_pages_exact(virt, unit_size_bytes); > + return -ENXIO; > + } > + } > + > + addr_range = phys & RMI_ADDR_RANGE_ADDR_MASK; > + FIELD_MODIFY(RMI_ADDR_RANGE_SIZE_MASK, &addr_range, unit_size); > + FIELD_MODIFY(RMI_ADDR_RANGE_COUNT_MASK, &addr_range, 1); > + FIELD_MODIFY(RMI_ADDR_RANGE_STATE_MASK, &addr_range, state); > + > + sro->addr_list[sro->addr_count++] = addr_range; > + found++; > + } > + > + regs.a2 = virt_to_phys(&sro->addr_list[addr_list_start]); > + regs.a3 = found; > + rmi_smccc_invoke(®s, out_regs); > + > + unsigned long donated_granules = out_regs->a1; > + > + if (WARN_ON(donated_granules & ((unit_size_bytes >> PAGE_SHIFT) - 1))) { > + /* > + * FIXME: RMM has only consumed part of a huge page, this leaks > + * the rest of the huge page > + */ > + donated_granules = ALIGN(donated_granules, > + (unit_size_bytes >> PAGE_SHIFT)); > + } > + unsigned long donated_blocks = donated_granules / (unit_size_bytes >> PAGE_SHIFT); > + > + if (WARN_ON(donated_blocks > found)) > + donated_blocks = found; > + > + unsigned long undonated_blocks = found - donated_blocks; > + > + while (donated_blocks && undonated_blocks) { > + sro->addr_count--; > + swap(sro->addr_list[addr_list_start], > + sro->addr_list[sro->addr_count]); > + addr_list_start++; > + > + donated_blocks--; > + undonated_blocks--; > + } > + sro->addr_count -= donated_blocks; > + > + return 0; > +} > + > +static int rmi_sro_donate(struct rmi_sro_state *sro, > + unsigned long sro_handle, > + unsigned long donatereq, > + struct arm_smccc_1_2_regs *regs, > + gfp_t gfp) > +{ > + unsigned long count = RMI_DONATE_COUNT(donatereq); > + > + if (WARN_ON(!count)) > + return 0; > + > + if (RMI_DONATE_CONTIG(donatereq)) { > + return rmi_sro_donate_contig(sro, sro_handle, donatereq, > + regs, gfp); > + } else { > + return rmi_sro_donate_noncontig(sro, sro_handle, donatereq, > + regs, gfp); > + } > +} > + > +static int rmi_sro_reclaim(struct rmi_sro_state *sro, > + unsigned long sro_handle, > + struct arm_smccc_1_2_regs *out_regs) > +{ > + unsigned long capacity; > + struct arm_smccc_1_2_regs regs; > + int ret; > + > + ret = rmi_sro_ensure_capacity(sro, 1); > + if (ret) > + rmi_sro_free(sro); > + > + capacity = RMI_MAX_ADDR_LIST - sro->addr_count; > + > + regs = (struct arm_smccc_1_2_regs){ > + SMC_RMI_OP_MEM_RECLAIM, > + sro_handle, > + virt_to_phys(&sro->addr_list[sro->addr_count]), > + capacity > + }; > + rmi_smccc_invoke(®s, out_regs); > + > + if (WARN_ON_ONCE(out_regs->a1 > capacity)) > + out_regs->a1 = capacity; > + > + sro->addr_count += out_regs->a1; > + > + return 0; > +} > + > +void rmi_sro_free(struct rmi_sro_state *sro) > +{ > + for (int i = 0; i < sro->addr_count; i++) { > + unsigned long entry = sro->addr_list[i]; > + unsigned long addr = RMI_ADDR_RANGE_ADDR(entry); > + unsigned long unit_size = RMI_ADDR_RANGE_SIZE(entry); > + unsigned long count = RMI_ADDR_RANGE_COUNT(entry); > + unsigned long state = RMI_ADDR_RANGE_STATE(entry); > + unsigned long size = donate_req_to_size(unit_size) * count; > + > + if (state == RMI_OP_MEM_DELEGATED) { > + if (WARN_ON(rmi_undelegate_range(addr, size))) { > + /* Leak the pages */ > + continue; > + } > + } > + free_pages_exact(phys_to_virt(addr), size); > + } > + > + sro->addr_count = 0; > +} > + > +unsigned long rmi_sro_execute(struct rmi_sro_state *sro, gfp_t gfp) > +{ > + unsigned long sro_handle; > + struct arm_smccc_1_2_regs regs; > + struct arm_smccc_1_2_regs *regs_in = &sro->regs; > + > + rmi_smccc_invoke(regs_in, ®s); > + > + sro_handle = regs.a1; > + > + while (RMI_RETURN_STATUS(regs.a0) == RMI_INCOMPLETE) { > + bool can_cancel = RMI_RETURN_CAN_CANCEL(regs.a0); > + int ret; > + > + switch (RMI_RETURN_MEMREQ(regs.a0)) { > + case RMI_OP_MEM_REQ_NONE: > + regs = (struct arm_smccc_1_2_regs){ > + SMC_RMI_OP_CONTINUE, sro_handle, 0 > + }; > + rmi_smccc_invoke(®s, ®s); > + break; 'ret' isn't initialized for case RMI_OP_MEM_REQ_NONE. > + case RMI_OP_MEM_REQ_DONATE: > + ret = rmi_sro_donate(sro, sro_handle, regs.a2, ®s, > + gfp); > + break; > + case RMI_OP_MEM_REQ_RECLAIM: > + ret = rmi_sro_reclaim(sro, sro_handle, ®s); > + break; > + default: > + ret = WARN_ON(1); > + break; > + } > + > + if (ret) { > + if (can_cancel) { > + /* > + * FIXME: Handle cancelling properly! > + * > + * If the operation has failed due to memory > + * allocation failure then the information on > + * the memory allocation should be saved, so > + * that the allocation can be repeated outside > + * of any context which prevented the > + * allocation. > + */ > + } > + if (WARN_ON(ret)) > + return ret; > + } > + } > + > + return regs.a0; > +} > + > static int rmi_check_version(void) > { > struct arm_smccc_res res; Thanks, Gavin