From: Hanjun Guo <guohanjun@huawei.com>
To: Jamie Nguyen <jamien@nvidia.com>,
Lorenzo Pieralisi <lpieralisi@kernel.org>,
Sudeep Holla <sudeep.holla@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
"Rafael J . Wysocki" <rafael@kernel.org>
Cc: Len Brown <lenb@kernel.org>, Dat Mach <dmach@nvidia.com>,
<linux-acpi@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 2/3] ACPI: arm64: Add support for the FF-A FFH Operation Region (offset 2)
Date: Mon, 21 Sep 2026 17:54:27 +0800 [thread overview]
Message-ID: <6ed517b2-90e8-8654-757e-6c0730b7d321@huawei.com> (raw)
In-Reply-To: <20260901192906.133670-3-jamien@nvidia.com>
On 2026/9/2 3:29, Jamie Nguyen wrote:
> Arm DEN0048D (Functional Fixed Hardware Specification v1.3, March 2026)
> added a third FFH Operation Region flavour. An Operation Region declared
> with an Offset of 0x2 triggers an FFA_MSG_SEND_DIRECT_REQ2 call instead of
> a bare SMC or HVC, and each 64-bit field of the region is one register,
> starting at X0:
>
> X0 call status, populated by OSPM on return
> X1 Bits[15:0] receiver endpoint ID, or zero to have OSPM
> resolve it from the service UUID
> X2-X3 service UUID of the callee partition, written by ACPI
> platform firmware using ToUUID()
> X4-X17 message payload, X4 is always present
>
> DEN0048D recommends Offset 0x2 for new platforms, since not every OSPM
> implements Offsets 0x0 and 0x1. Linux implements both and rejects anything
> else, so AML using the recommended encoding simply fails today.
>
> Add the Operation Region side of it. Region length validation, the X0-X17
> layout, the ToUUID() to FF-A UUID byte order conversion and the DEN0048D
> table 3 status codes all live here; they are ACPI semantics, not FF-A
> ones. The call itself goes out through a small set of ops that the FF-A
> driver registers. That indirection is needed because this file is built
> in, while CONFIG_ARM_FFA_TRANSPORT is a tristate.
>
> Anything that stops the call being made comes back to AML in the X0 status
> field: a malformed region length, or a null service UUID when AML has
> asked OSPM to find the endpoint itself. Once the call has gone out every
> register is copied back, whatever the outcome, which is what DEN0048D
> requires. That also takes care of table 3, because FFA_ERROR reports the
> FF-A error code in X2 and FFH_FFA_CALL_FAILED wants it in the same place.
> A response that is neither FFA_ERROR nor FFA_MSG_SEND_DIRECT_RESP2 is
> handled the same way; the call did complete.
>
> Assisted-by: Claude:claude-opus-5
> Co-developed-by: Dat Mach <dmach@nvidia.com>
> Signed-off-by: Dat Mach <dmach@nvidia.com>
> Signed-off-by: Jamie Nguyen <jamien@nvidia.com>
> ---
> drivers/acpi/arm64/ffh.c | 185 +++++++++++++++++++++++++++++++++++++++
> include/linux/acpi.h | 41 +++++++++
> 2 files changed, 226 insertions(+)
>
> diff --git a/drivers/acpi/arm64/ffh.c b/drivers/acpi/arm64/ffh.c
> index 04380bab193df..9f8a508cf2d4a 100644
> --- a/drivers/acpi/arm64/ffh.c
> +++ b/drivers/acpi/arm64/ffh.c
> @@ -1,7 +1,9 @@
> // SPDX-License-Identifier: GPL-2.0-only
> #include <linux/acpi.h>
> #include <linux/arm-smccc.h>
> +#include <linux/rwsem.h>
> #include <linux/slab.h>
> +#include <linux/uuid.h>
>
> /*
> * Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
> @@ -62,6 +64,183 @@ static bool acpi_ffh_smccc_owner_allowed(u32 fid)
> return false;
> }
>
> +/*
> + * FFH Operation Regions declared with an Offset of 0x2 trigger an
> + * FFA_MSG_SEND_DIRECT_REQ2 call, as described in Arm DEN0048D (Functional
> + * Fixed Hardware Specification v1.3) section 2.3.1.2. Every 64-bit field of
> + * the region maps to one register, ordered from X0:
> + *
> + * X0 status, one of the ACPI_FFH_FFA_* codes below, populated by
> + * OSPM on return
> + * X1 Bits[15:0] hold the receiver endpoint ID, or zero to have OSPM
> + * resolve it from the service UUID
> + * X2-X3 service UUID of the callee partition, written by ACPI platform
> + * firmware with the ToUUID() ASL operator
> + * X4-X17 message payload, X4 is always present
> + *
> + * The region Length is "32 + 8 * N" bytes with 1 <= N <= 14, which is X0-X4
> + * at minimum and X0-X17 at most.
> + */
> +#define ACPI_FFH_FFA_HDR_REGS 4 /* X0 - X3 */
> +#define ACPI_FFH_FFA_MAX_PAYLOAD_REGS 14 /* X4 - X17 */
> +#define ACPI_FFH_FFA_UUID_OFFSET (2 * sizeof(u64))
> +#define ACPI_FFH_FFA_MIN_LENGTH ((ACPI_FFH_FFA_HDR_REGS + 1) * sizeof(u64))
> +#define ACPI_FFH_FFA_MAX_LENGTH \
> + ((ACPI_FFH_FFA_HDR_REGS + ACPI_FFH_FFA_MAX_PAYLOAD_REGS) * sizeof(u64))
> +
> +/* DEN0048D table 3, FFH Operation Region status codes for FFA calls */
> +#define ACPI_FFH_FFA_CALL_FAILED 1
> +#define ACPI_FFH_FFA_SUCCESS 0
> +#define ACPI_FFH_FFA_NOT_SUPPORTED (-1)
> +#define ACPI_FFH_FFA_INVALID_PARAMETERS (-2)
> +#define ACPI_FFH_FFA_OUT_OF_MEMORY (-3)
> +#define ACPI_FFH_FFA_UNSPECIFIED_ERROR (-4)
> +
> +static const struct acpi_ffh_ffa_ops *ffa_ops;
> +static DECLARE_RWSEM(ffa_ops_sem);
> +
> +int acpi_ffh_ffa_register(const struct acpi_ffh_ffa_ops *ops)
> +{
> + int ret = 0;
> +
> + if (!ops || !ops->partition_id || !ops->direct_req2)
> + return -EINVAL;
> +
> + down_write(&ffa_ops_sem);
> + if (ffa_ops)
> + ret = -EBUSY;
> + else
> + ffa_ops = ops;
> + up_write(&ffa_ops_sem);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(acpi_ffh_ffa_register);
> +
> +void acpi_ffh_ffa_unregister(const struct acpi_ffh_ffa_ops *ops)
> +{
> + down_write(&ffa_ops_sem);
> + if (ffa_ops == ops)
> + ffa_ops = NULL;
> + up_write(&ffa_ops_sem);
> +}
> +EXPORT_SYMBOL_GPL(acpi_ffh_ffa_unregister);
> +
> +/*
> + * ToUUID() emits the UUID in mixed-endian (EFI GUID) byte order whereas FF-A
> + * expects the RFC4122 layout, which is exactly a guid_t to uuid_t conversion.
> + */
> +static void acpi_ffh_ffa_uuid(uuid_t *uuid, const u8 *aml_buf)
> +{
> + int i;
> +
> + for (i = 0; i < UUID_SIZE; i++)
> + uuid->b[i] = aml_buf[guid_index[i]];
> +}
> +
> +static int acpi_ffh_ffa_status(int err)
> +{
> + switch (err) {
> + case 0:
> + return ACPI_FFH_FFA_SUCCESS;
> + case -EIO:
> + case -EPROTO:
> + return ACPI_FFH_FFA_CALL_FAILED;
> + case -EOPNOTSUPP:
> + return ACPI_FFH_FFA_NOT_SUPPORTED;
> + case -EINVAL:
> + case -ENOENT:
> + case -ENODEV:
> + case -ENOTUNIQ:
> + return ACPI_FFH_FFA_INVALID_PARAMETERS;
> + case -ENOMEM:
> + return ACPI_FFH_FFA_OUT_OF_MEMORY;
> + default:
> + return ACPI_FFH_FFA_UNSPECIFIED_ERROR;
> + }
> +}
> +
> +static bool acpi_ffh_ffa_length_valid(u64 length)
> +{
> + return length >= ACPI_FFH_FFA_MIN_LENGTH &&
> + length <= ACPI_FFH_FFA_MAX_LENGTH &&
> + !(length % sizeof(u64));
> +}
> +
> +static void acpi_ffh_ffa_handler(struct acpi_ffh_info *info, void *value)
> +{
> + int status = ACPI_FFH_FFA_INVALID_PARAMETERS;
> + u64 resp_regs[3] = {};
> + unsigned int nr_payload;
> + u64 *regs = value;
> + uuid_t uuid;
> + u16 dst_id;
> + int ret;
> +
> + if (!acpi_ffh_ffa_length_valid(info->length))
> + goto out;
> +
> + nr_payload = info->length / sizeof(u64) - ACPI_FFH_FFA_HDR_REGS;
> +
> + acpi_ffh_ffa_uuid(&uuid, (u8 *)value + ACPI_FFH_FFA_UUID_OFFSET);
> +
> + down_read(&ffa_ops_sem);
> + if (!ffa_ops) {
> + status = ACPI_FFH_FFA_NOT_SUPPORTED;
> + goto out_unlock;
> + }
> +
> + /*
> + * A zero receiver endpoint ID means ACPI platform firmware expects
> + * OSPM to derive it from the service UUID.
> + */
> + dst_id = regs[1] & GENMASK(15, 0);
> + if (!dst_id) {
> + /*
> + * A null UUID means "every partition" to
> + * FFA_PARTITION_INFO_GET, so reject it here rather than let a
> + * bare read of the Operation Region, which arrives as a zeroed
> + * buffer, resolve to an arbitrary endpoint.
> + */
> + if (uuid_is_null(&uuid))
> + goto out_unlock;
> +
> + ret = ffa_ops->partition_id(&uuid, &dst_id);
> + if (ret) {
> + status = acpi_ffh_ffa_status(ret);
> + goto out_unlock;
> + }
> + }
> +
> + ret = ffa_ops->direct_req2(dst_id, &uuid, regs + ACPI_FFH_FFA_HDR_REGS,
> + nr_payload, resp_regs);
> + status = acpi_ffh_ffa_status(ret);
> +
> + /*
> + * DEN0048D asks for the response registers to be copied back. That also
> + * takes care of table 3: FFA_ERROR reports the FF-A error code in X2,
> + * which is exactly where FFH_FFA_CALL_FAILED wants it. -EIO and -EPROTO
> + * both mean the call completed, so the registers hold the callee's
> + * response and not AML's own request.
> + */
> + if (!ret || ret == -EIO || ret == -EPROTO) {
> + regs[1] = resp_regs[0];
> + regs[2] = resp_regs[1];
> + regs[3] = resp_regs[2];
> + }
> +
> +out_unlock:
> + up_read(&ffa_ops_sem);
> +out:
> + /*
> + * DEN0048D describes this field as 64 bits wide and gives the table 3
> + * codes as signed values, so sign extend rather than write a narrower
> + * quantity. 0xfffe or 0xfffffffe would read back as a positive number
> + * in a 64-bit AML comparison.
> + */
> + regs[0] = (u64)(s64)status;
> +}
> +
> int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
> {
> int ret = 0;
> @@ -99,6 +278,12 @@ int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_contex
> ffh_ctxt->invoke_ffh64_fn(r, r);
> memcpy(value, r, ffh_ctxt->info.length);
> }
> + } else if (ffh_ctxt->info.offset == 2) {
> + /* FFA_MSG_SEND_DIRECT_REQ2 call */
> + if (ffh_ctxt->info.length < sizeof(u64))
> + ret = AE_ERROR;
There is a acpi_ffh_ffa_length_valid() check in acpi_ffh_ffa_handler(),
is it a duplicated one here?
> + else
> + acpi_ffh_ffa_handler(&ffh_ctxt->info, value);
Thanks
Hanjun
next prev parent reply other threads:[~2026-09-21 9:54 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 19:29 [PATCH v2 0/3] ACPI: arm64: FFH Operation Region support for FF-A " Jamie Nguyen
2026-09-01 19:29 ` [PATCH v2 1/3] firmware: arm_ffa: Split the response out of ffa_msg_send_direct_req2() Jamie Nguyen
2026-09-21 9:41 ` Hanjun Guo
2026-09-21 17:49 ` Jamie Nguyen
2026-09-01 19:29 ` [PATCH v2 2/3] ACPI: arm64: Add support for the FF-A FFH Operation Region (offset 2) Jamie Nguyen
2026-09-21 9:54 ` Hanjun Guo [this message]
2026-09-21 17:49 ` Jamie Nguyen
2026-09-01 19:29 ` [PATCH v2 3/3] firmware: arm_ffa: Back the ACPI FF-A FFH Operation Region Jamie Nguyen
2026-09-18 16:14 ` [PATCH v2 0/3] ACPI: arm64: FFH Operation Region support for FF-A (offset 2) Jamie Nguyen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=6ed517b2-90e8-8654-757e-6c0730b7d321@huawei.com \
--to=guohanjun@huawei.com \
--cc=catalin.marinas@arm.com \
--cc=dmach@nvidia.com \
--cc=jamien@nvidia.com \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=rafael@kernel.org \
--cc=sudeep.holla@kernel.org \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®