2023-08-03 20:08:30

by Sudeep Holla

[permalink] [raw]
Subject: [PATCH RFT 00/12] firmware: arm_ffa: Add FF-A v1.1 notifications support

The series adds initial support for the notifications added in FF-A v1.1
The notification mechanism enables a requester/sender endpoint to notify
a service provider/receiver endpoint about an event with non-blocking
semantics.

A notification is akin to the doorbell between two endpoints in a
communication protocol that is based upon the doorbell/mailbox mechanism.

The framework is responsible for the delivery of the notification from the
sender to the receiver without blocking the sender. The receiver endpoint
relies on the OS scheduler for allocation of CPU cycles to handle a
notification.

OS is referred as the receiver’s scheduler in the context of notifications.
The framework is responsible for informing the receiver’s scheduler that
the receiver must be run since it has a pending notification.

Signed-off-by: Sudeep Holla <[email protected]>
---
Sudeep Holla (12):
firmware: arm_ffa: Update the FF-A command list with v1.1 additions
firmware: arm_ffa: Implement notification bitmap create and destroy interfaces
firmware: arm_ffa: Implement the notification bind and unbind interface
firmware: arm_ffa: Implement the FFA_RUN interface
firmware: arm_ffa: Implement the FFA_NOTIFICATION_SET interface
firmware: arm_ffa: Implement the FFA_NOTIFICATION_GET interface
firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface
firmware: arm_ffa: Initial support for scheduler receiver interrupt
firmware: arm_ffa: Add schedule receiver callback mechanism
firmware: arm_ffa: Add interfaces to request notification callbacks
firmware: arm_ffa: Add interface to send a notification to a given partition
firmware: arm_ffa: Add notification handling mechanism

drivers/firmware/arm_ffa/driver.c | 700 +++++++++++++++++++++++++++++++++++++-
include/linux/arm_ffa.h | 41 +++
2 files changed, 740 insertions(+), 1 deletion(-)
---
base-commit: 5d0c230f1de8c7515b6567d9afba1f196fb4e2f4
change-id: 20230803-ffa_v1-1_notif-e11bc9459962

Best regards,
--
Regards,
Sudeep



2023-08-03 20:11:03

by Sudeep Holla

[permalink] [raw]
Subject: [PATCH RFT 02/12] firmware: arm_ffa: Implement notification bitmap create and destroy interfaces

On systems without a hypervisor the responsibility of requesting the
creation of the notification bitmaps in the SPM falls to the FF-A driver.

We use FFA features to determine if the ABI is supported, if it is not
we can assume there is a hypervisor present and will take care of ensure
the relevant notifications bitmaps are created on this partitions behalf.

An endpoint’s notification bitmaps needs to be setup before it configures
its notifications and before other endpoints and partition managers can
start signaling these notifications.

Add interface to create and destroy the notification bitmaps and use the
same to do the necessary setup during the initialisation and cleanup
during the module exit.

Signed-off-by: Sudeep Holla <[email protected]>
---
drivers/firmware/arm_ffa/driver.c | 58 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 6fc83fa6b81c..022c893c9e06 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -84,6 +84,7 @@ struct ffa_drv_info {
void *rx_buffer;
void *tx_buffer;
bool mem_ops_native;
+ bool bitmap_created;
};

static struct ffa_drv_info *drv_info;
@@ -543,6 +544,37 @@ static int ffa_features(u32 func_feat_id, u32 input_props,
return 0;
}

+static int ffa_notification_bitmap_create(void)
+{
+ ffa_value_t ret;
+ u16 vcpu_count = nr_cpu_ids;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_NOTIFICATION_BITMAP_CREATE,
+ .a1 = drv_info->vm_id, .a2 = vcpu_count,
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ return 0;
+}
+
+static int ffa_notification_bitmap_destroy(void)
+{
+ ffa_value_t ret;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_NOTIFICATION_BITMAP_DESTROY,
+ .a1 = drv_info->vm_id,
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ return 0;
+}
+
static void ffa_set_up_mem_ops_native_flag(void)
{
if (!ffa_features(FFA_FN_NATIVE(MEM_LEND), 0, NULL, NULL) ||
@@ -700,6 +732,29 @@ static void ffa_setup_partitions(void)
kfree(pbuf);
}

+static int ffa_notifications_setup(void)
+{
+ int ret;
+
+ ret = ffa_features(FFA_NOTIFICATION_BITMAP_CREATE, 0, NULL, NULL);
+ if (!ret) {
+ ret = ffa_notification_bitmap_create();
+ if (ret) {
+ pr_err("notification_bitmap_create error %d\n", ret);
+ return ret;
+ }
+ }
+ drv_info->bitmap_created = true;
+
+ return 0;
+}
+
+static void ffa_notifications_cleanup(void)
+{
+ if (drv_info->bitmap_created)
+ ffa_notification_bitmap_destroy();
+}
+
static int __init ffa_init(void)
{
int ret;
@@ -755,7 +810,7 @@ static int __init ffa_init(void)

ffa_set_up_mem_ops_native_flag();

- return 0;
+ return ffa_notifications_setup();
free_pages:
if (drv_info->tx_buffer)
free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
@@ -770,6 +825,7 @@ subsys_initcall(ffa_init);

static void __exit ffa_exit(void)
{
+ ffa_notifications_cleanup();
ffa_rxtx_unmap(drv_info->vm_id);
free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE);

--
2.41.0


2023-08-03 20:21:03

by Sudeep Holla

[permalink] [raw]
Subject: [PATCH RFT 04/12] firmware: arm_ffa: Implement the FFA_RUN interface

FFA_RUN is used by a scheduler to allocate CPU cycles to a target
endpoint execution context specified in the target information parameter.

If the endpoint execution context is in the waiting/blocked state, it
transitions to the running state.

Expose the ability to call FFA_RUN in order to give any partition in the
system cpu cycles to perform IMPDEF functionality.

Signed-off-by: Sudeep Holla <[email protected]>
---
drivers/firmware/arm_ffa/driver.c | 22 ++++++++++++++++++++++
include/linux/arm_ffa.h | 5 +++++
2 files changed, 27 insertions(+)

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index a76e5d3a2422..41171ae7f63a 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -604,6 +604,23 @@ static int ffa_notification_bind_common(u16 dst_id, u64 bitmap,
return 0;
}

+static int ffa_run(struct ffa_device *dev, u16 vcpu)
+{
+ ffa_value_t ret;
+ u32 target = dev->vm_id << 16 | vcpu;
+
+ invoke_ffa_fn((ffa_value_t){ .a0 = FFA_RUN, .a1 = target, }, &ret);
+
+ while (ret.a0 == FFA_INTERRUPT)
+ invoke_ffa_fn((ffa_value_t){ .a0 = FFA_RUN, .a1 = ret.a1, },
+ &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ return 0;
+}
+
static void ffa_set_up_mem_ops_native_flag(void)
{
if (!ffa_features(FFA_FN_NATIVE(MEM_LEND), 0, NULL, NULL) ||
@@ -696,10 +713,15 @@ static const struct ffa_mem_ops ffa_drv_mem_ops = {
.memory_lend = ffa_memory_lend,
};

+static const struct ffa_cpu_ops ffa_drv_cpu_ops = {
+ .run = ffa_run,
+};
+
static const struct ffa_ops ffa_drv_ops = {
.info_ops = &ffa_drv_info_ops,
.msg_ops = &ffa_drv_msg_ops,
.mem_ops = &ffa_drv_mem_ops,
+ .cpu_ops = &ffa_drv_cpu_ops,
};

void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid)
diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h
index 2ea1717a0825..12fd134bf670 100644
--- a/include/linux/arm_ffa.h
+++ b/include/linux/arm_ffa.h
@@ -387,10 +387,15 @@ struct ffa_mem_ops {
int (*memory_lend)(struct ffa_mem_ops_args *args);
};

+struct ffa_cpu_ops {
+ int (*run)(struct ffa_device *dev, u16 vcpu);
+};
+
struct ffa_ops {
const struct ffa_info_ops *info_ops;
const struct ffa_msg_ops *msg_ops;
const struct ffa_mem_ops *mem_ops;
+ const struct ffa_cpu_ops *cpu_ops;
};

#endif /* _LINUX_ARM_FFA_H */

--
2.41.0


2023-08-03 20:53:31

by Sudeep Holla

[permalink] [raw]
Subject: [PATCH RFT 03/12] firmware: arm_ffa: Implement the notification bind and unbind interface

A receiver endpoint must bind a notification to any sender endpoint
before the latter can signal the notification to the former. The receiver
assigns one or more doorbells to a specific sender. Only the sender can
ring these doorbells.

A receiver uses the FFA_NOTIFICATION_BIND interface to bind one or more
notifications to the sender. A receiver un-binds a notification from a
sender endpoint to stop the notification from being signaled. It uses
the FFA_NOTIFICATION_UNBIND interface to do this.

Allow the FF-A driver to be able to bind and unbind a given notification
ID to a specific partition ID. This will be used to register and
unregister notification callbacks from the FF-A client drivers.

Signed-off-by: Sudeep Holla <[email protected]>
---
drivers/firmware/arm_ffa/driver.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 022c893c9e06..a76e5d3a2422 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -575,6 +575,35 @@ static int ffa_notification_bitmap_destroy(void)
return 0;
}

+#define NOTIFICATION_LOW_MASK GENMASK(31, 0)
+#define NOTIFICATION_HIGH_MASK GENMASK(63, 32)
+#define NOTIFICATION_BITMAP_HIGH(x) \
+ ((u32)(FIELD_GET(NOTIFICATION_HIGH_MASK, (x))))
+#define NOTIFICATION_BITMAP_LOW(x) \
+ ((u32)(FIELD_GET(NOTIFICATION_LOW_MASK, (x))))
+
+static int ffa_notification_bind_common(u16 dst_id, u64 bitmap,
+ u32 flags, bool is_bind)
+{
+ ffa_value_t ret;
+ u32 func, src_dst_ids = PACK_TARGET_INFO(dst_id, drv_info->vm_id);
+
+ func = is_bind ? FFA_NOTIFICATION_BIND : FFA_NOTIFICATION_UNBIND;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = func, .a1 = src_dst_ids, .a2 = flags,
+ .a3 = NOTIFICATION_BITMAP_LOW(bitmap),
+ .a4 = NOTIFICATION_BITMAP_HIGH(bitmap),
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+ else if (ret.a0 != FFA_SUCCESS)
+ return -EINVAL;
+
+ return 0;
+}
+
static void ffa_set_up_mem_ops_native_flag(void)
{
if (!ffa_features(FFA_FN_NATIVE(MEM_LEND), 0, NULL, NULL) ||

--
2.41.0


2023-08-03 20:54:52

by Sudeep Holla

[permalink] [raw]
Subject: [PATCH RFT 01/12] firmware: arm_ffa: Update the FF-A command list with v1.1 additions

Arm Firmware Framework for A-profile(FFA) v1.1 introduces notifications
and indirect messaging based upon notifications support and extends some
of the memory interfaces.

Let us add all the newly supported FF-A function IDs in the spec.
Also update to the error values and associated handling.

Signed-off-by: Sudeep Holla <[email protected]>
---
drivers/firmware/arm_ffa/driver.c | 3 ++-
include/linux/arm_ffa.h | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 2109cd178ff7..6fc83fa6b81c 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -64,6 +64,7 @@ static const int ffa_linux_errmap[] = {
-EACCES, /* FFA_RET_DENIED */
-EAGAIN, /* FFA_RET_RETRY */
-ECANCELED, /* FFA_RET_ABORTED */
+ -ENODATA, /* FFA_RET_NO_DATA */
};

static inline int ffa_to_linux_errno(int errno)
@@ -336,7 +337,7 @@ static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz,
if (ret.a0 == FFA_ERROR)
return ffa_to_linux_errno((int)ret.a2);

- if (ret.a0 == FFA_SUCCESS) {
+ if (ret.a0 == FFA_SUCCESS || ret.a0 == FFA_FN64_SUCCESS) {
if (handle)
*handle = PACK_HANDLE(ret.a2, ret.a3);
} else if (ret.a0 == FFA_MEM_FRAG_RX) {
diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h
index cc060da51bec..2ea1717a0825 100644
--- a/include/linux/arm_ffa.h
+++ b/include/linux/arm_ffa.h
@@ -20,6 +20,7 @@

#define FFA_ERROR FFA_SMC_32(0x60)
#define FFA_SUCCESS FFA_SMC_32(0x61)
+#define FFA_FN64_SUCCESS FFA_SMC_64(0x61)
#define FFA_INTERRUPT FFA_SMC_32(0x62)
#define FFA_VERSION FFA_SMC_32(0x63)
#define FFA_FEATURES FFA_SMC_32(0x64)
@@ -54,6 +55,23 @@
#define FFA_MEM_FRAG_RX FFA_SMC_32(0x7A)
#define FFA_MEM_FRAG_TX FFA_SMC_32(0x7B)
#define FFA_NORMAL_WORLD_RESUME FFA_SMC_32(0x7C)
+#define FFA_NOTIFICATION_BITMAP_CREATE FFA_SMC_32(0x7D)
+#define FFA_NOTIFICATION_BITMAP_DESTROY FFA_SMC_32(0x7E)
+#define FFA_NOTIFICATION_BIND FFA_SMC_32(0x7F)
+#define FFA_NOTIFICATION_UNBIND FFA_SMC_32(0x80)
+#define FFA_NOTIFICATION_SET FFA_SMC_32(0x81)
+#define FFA_NOTIFICATION_GET FFA_SMC_32(0x82)
+#define FFA_NOTIFICATION_INFO_GET FFA_SMC_32(0x83)
+#define FFA_FN64_NOTIFICATION_INFO_GET FFA_SMC_64(0x83)
+#define FFA_RX_ACQUIRE FFA_SMC_32(0x84)
+#define FFA_SPM_ID_GET FFA_SMC_32(0x85)
+#define FFA_MSG_SEND2 FFA_SMC_32(0x86)
+#define FFA_SECONDARY_EP_REGISTER FFA_SMC_32(0x87)
+#define FFA_FN64_SECONDARY_EP_REGISTER FFA_SMC_64(0x87)
+#define FFA_MEM_PERM_GET FFA_SMC_32(0x88)
+#define FFA_FN64_MEM_PERM_GET FFA_SMC_64(0x88)
+#define FFA_MEM_PERM_SET FFA_SMC_32(0x89)
+#define FFA_FN64_MEM_PERM_SET FFA_SMC_64(0x89)

/*
* For some calls it is necessary to use SMC64 to pass or return 64-bit values.
@@ -76,6 +94,7 @@
#define FFA_RET_DENIED (-6)
#define FFA_RET_RETRY (-7)
#define FFA_RET_ABORTED (-8)
+#define FFA_RET_NO_DATA (-9)

/* FFA version encoding */
#define FFA_MAJOR_VERSION_MASK GENMASK(30, 16)
@@ -86,6 +105,7 @@
(FIELD_PREP(FFA_MAJOR_VERSION_MASK, (major)) | \
FIELD_PREP(FFA_MINOR_VERSION_MASK, (minor)))
#define FFA_VERSION_1_0 FFA_PACK_VERSION_INFO(1, 0)
+#define FFA_VERSION_1_1 FFA_PACK_VERSION_INFO(1, 1)

/**
* FF-A specification mentions explicitly about '4K pages'. This should

--
2.41.0


2023-09-12 13:30:25

by Jens Wiklander

[permalink] [raw]
Subject: Re: [PATCH RFT 03/12] firmware: arm_ffa: Implement the notification bind and unbind interface

On Thu, Aug 03, 2023 at 08:02:07PM +0100, Sudeep Holla wrote:
> A receiver endpoint must bind a notification to any sender endpoint
> before the latter can signal the notification to the former. The receiver
> assigns one or more doorbells to a specific sender. Only the sender can
> ring these doorbells.
>
> A receiver uses the FFA_NOTIFICATION_BIND interface to bind one or more
> notifications to the sender. A receiver un-binds a notification from a
> sender endpoint to stop the notification from being signaled. It uses
> the FFA_NOTIFICATION_UNBIND interface to do this.
>
> Allow the FF-A driver to be able to bind and unbind a given notification
> ID to a specific partition ID. This will be used to register and
> unregister notification callbacks from the FF-A client drivers.
>
> Signed-off-by: Sudeep Holla <[email protected]>
> ---
> drivers/firmware/arm_ffa/driver.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
> index 022c893c9e06..a76e5d3a2422 100644
> --- a/drivers/firmware/arm_ffa/driver.c
> +++ b/drivers/firmware/arm_ffa/driver.c
> @@ -575,6 +575,35 @@ static int ffa_notification_bitmap_destroy(void)
> return 0;
> }
>
> +#define NOTIFICATION_LOW_MASK GENMASK(31, 0)
> +#define NOTIFICATION_HIGH_MASK GENMASK(63, 32)
> +#define NOTIFICATION_BITMAP_HIGH(x) \
> + ((u32)(FIELD_GET(NOTIFICATION_HIGH_MASK, (x))))
> +#define NOTIFICATION_BITMAP_LOW(x) \
> + ((u32)(FIELD_GET(NOTIFICATION_LOW_MASK, (x))))
> +
> +static int ffa_notification_bind_common(u16 dst_id, u64 bitmap,
> + u32 flags, bool is_bind)
> +{
> + ffa_value_t ret;
> + u32 func, src_dst_ids = PACK_TARGET_INFO(dst_id, drv_info->vm_id);
dst_id and drv_info->vm_id should be swapped in the argument to
PACK_TARGET_INFO().

Thanks,
Jens

> +
> + func = is_bind ? FFA_NOTIFICATION_BIND : FFA_NOTIFICATION_UNBIND;
> +
> + invoke_ffa_fn((ffa_value_t){
> + .a0 = func, .a1 = src_dst_ids, .a2 = flags,
> + .a3 = NOTIFICATION_BITMAP_LOW(bitmap),
> + .a4 = NOTIFICATION_BITMAP_HIGH(bitmap),
> + }, &ret);
> +
> + if (ret.a0 == FFA_ERROR)
> + return ffa_to_linux_errno((int)ret.a2);
> + else if (ret.a0 != FFA_SUCCESS)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> static void ffa_set_up_mem_ops_native_flag(void)
> {
> if (!ffa_features(FFA_FN_NATIVE(MEM_LEND), 0, NULL, NULL) ||
>
> --
> 2.41.0
>

2023-09-12 16:17:40

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH RFT 03/12] firmware: arm_ffa: Implement the notification bind and unbind interface

On Tue, Sep 12, 2023 at 03:23:53PM +0200, Jens Wiklander wrote:
> On Thu, Aug 03, 2023 at 08:02:07PM +0100, Sudeep Holla wrote:
> > A receiver endpoint must bind a notification to any sender endpoint
> > before the latter can signal the notification to the former. The receiver
> > assigns one or more doorbells to a specific sender. Only the sender can
> > ring these doorbells.
> >
> > A receiver uses the FFA_NOTIFICATION_BIND interface to bind one or more
> > notifications to the sender. A receiver un-binds a notification from a
> > sender endpoint to stop the notification from being signaled. It uses
> > the FFA_NOTIFICATION_UNBIND interface to do this.
> >
> > Allow the FF-A driver to be able to bind and unbind a given notification
> > ID to a specific partition ID. This will be used to register and
> > unregister notification callbacks from the FF-A client drivers.
> >
> > Signed-off-by: Sudeep Holla <[email protected]>
> > ---
> > drivers/firmware/arm_ffa/driver.c | 29 +++++++++++++++++++++++++++++
> > 1 file changed, 29 insertions(+)
> >
> > diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
> > index 022c893c9e06..a76e5d3a2422 100644
> > --- a/drivers/firmware/arm_ffa/driver.c
> > +++ b/drivers/firmware/arm_ffa/driver.c
> > @@ -575,6 +575,35 @@ static int ffa_notification_bitmap_destroy(void)
> > return 0;
> > }
> >
> > +#define NOTIFICATION_LOW_MASK GENMASK(31, 0)
> > +#define NOTIFICATION_HIGH_MASK GENMASK(63, 32)
> > +#define NOTIFICATION_BITMAP_HIGH(x) \
> > + ((u32)(FIELD_GET(NOTIFICATION_HIGH_MASK, (x))))
> > +#define NOTIFICATION_BITMAP_LOW(x) \
> > + ((u32)(FIELD_GET(NOTIFICATION_LOW_MASK, (x))))
> > +
> > +static int ffa_notification_bind_common(u16 dst_id, u64 bitmap,
> > + u32 flags, bool is_bind)
> > +{
> > + ffa_value_t ret;
> > + u32 func, src_dst_ids = PACK_TARGET_INFO(dst_id, drv_info->vm_id);
> dst_id and drv_info->vm_id should be swapped in the argument to
> PACK_TARGET_INFO().
>

Thanks a lot for having a look at the series. I see Olivier or someone
have already pointed this in private and I seem to have it fixed locally
already.

--
Regards,
Sudeep