diff mbox series

[3/3] firmware: arm_ffa: Add support for handling notification pending interrupt(NPI)

Message ID 20240410-ffa_npi_support-v1-3-1a5223391bd1@arm.com (mailing list archive)
State New, archived
Headers show
Series firmware: arm_ffa: Add support to run inside a guest/VM under a hypervisor | expand

Commit Message

Sudeep Holla April 10, 2024, 11:39 a.m. UTC
The FF-A uses the notification pending interrupt to inform the receiver
that it has a pending notification. This is a virtual interrupt and is
used by the following type of receivers:
 1. A guest/VM running under a hypervisor.
 2. An S-EL1 SP running under a S-EL2 SPMC.

The rules that govern the properties of the NPI are the same as the
rules for the SRI with couple of exceptions. If the SRI is not supported,
then an attempt to discover NPI will be made in the driver.

The handling of NPI is also same as the handling of notification for the
self/primary VM with ID 0 except the absence of global notification.

Co-Developed-by: Jens Wiklander <jens.wiklander@linaro.org>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
 drivers/firmware/arm_ffa/driver.c | 43 +++++++++++++++++++++++++++++++--------
 1 file changed, 34 insertions(+), 9 deletions(-)

Comments

Sudeep Holla April 11, 2024, 9:54 a.m. UTC | #1
On Wed, Apr 10, 2024 at 12:39:48PM +0100, Sudeep Holla wrote:
> The FF-A uses the notification pending interrupt to inform the receiver
> that it has a pending notification. This is a virtual interrupt and is
> used by the following type of receivers:
>  1. A guest/VM running under a hypervisor.
>  2. An S-EL1 SP running under a S-EL2 SPMC.
> 
> The rules that govern the properties of the NPI are the same as the
> rules for the SRI with couple of exceptions. If the SRI is not supported,
> then an attempt to discover NPI will be made in the driver.
> 
> The handling of NPI is also same as the handling of notification for the
> self/primary VM with ID 0 except the absence of global notification.
>

OK I think I rushed to send this. Bertrand had now convinced me with a
use case that needs the support for both SRI and NPI in the driver.
XEN hypervisor can inject both SRI and NPI to the Dom0. The choice of
NPI over SRI is to avoid the context switch latency with the
FFA_NOTIFICATION_INFO_GET as NPI will just need FFA_NOTIFICATION_GET
which may completely avoid switching to secure side as XEN hyp handles
the same.

--
Regards,
Sudeep
diff mbox series

Patch

diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index c299cb9e6889..d50b41a815b9 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -100,6 +100,8 @@  struct ffa_drv_info {
 	bool mem_ops_native;
 	bool bitmap_created;
 	bool notif_enabled;
+	/* Flag to indicate it is Notification pending interrupt */
+	bool irq_is_npi;
 	/* Schedule Receiver(SRI) or Notification pending interrupt(NPI) */
 	unsigned int sr_or_np_irq;
 	unsigned int cpuhp_state;
@@ -1138,6 +1140,15 @@  ffa_self_notif_handle(u16 vcpu, bool is_per_vcpu, void *cb_data)
 			      &info->notif_pcpu_work);
 }
 
+static irqreturn_t npi_handler(int irq, void *irq_data)
+{
+	struct ffa_pcpu_irq *pcpu = irq_data;
+
+	ffa_self_notif_handle(smp_processor_id(), true, pcpu->info);
+
+	return IRQ_HANDLED;
+}
+
 static const struct ffa_info_ops ffa_drv_info_ops = {
 	.api_version_get = ffa_api_version_get,
 	.partition_info_get = ffa_partition_info_get,
@@ -1307,16 +1318,24 @@  static void ffa_sched_recv_irq_work_fn(struct work_struct *work)
 	ffa_notification_info_get();
 }
 
-static int ffa_sr_or_np_irq_map(void)
+static int ffa_sr_or_np_irq_map(bool *irq_is_npi)
 {
 	int ret, irq, intr_id;
 
 	/* The returned intr_id is assumed to be SGI donated to NS world */
 	ret = ffa_features(FFA_FEAT_SCHEDULE_RECEIVER_INT, 0, &intr_id, NULL);
-	if (ret < 0) {
-		if (ret != -EOPNOTSUPP)
-			pr_err("Failed to retrieve scheduler Rx interrupt\n");
+	if (ret && ret != -EOPNOTSUPP) {
+		pr_err("Failed to retrieve scheduler Rx interrupt\n");
 		return ret;
+	} else if (ret) {
+		ret = ffa_features(FFA_FEAT_NOTIFICATION_PENDING_INT, 0,
+				   &intr_id, NULL);
+		if (ret) {
+			if (ret != -EOPNOTSUPP)
+				pr_err("Failed to retrieve notification pending interrupt\n");
+			return ret;
+		}
+		*irq_is_npi = true;
 	}
 
 	if (acpi_disabled) {
@@ -1389,7 +1408,7 @@  static void ffa_uninit_pcpu_irq(void)
 	}
 }
 
-static int ffa_init_pcpu_irq(unsigned int irq)
+static int ffa_init_pcpu_irq(void)
 {
 	struct ffa_pcpu_irq __percpu *irq_pcpu;
 	int ret, cpu;
@@ -1403,9 +1422,15 @@  static int ffa_init_pcpu_irq(unsigned int irq)
 
 	drv_info->irq_pcpu = irq_pcpu;
 
-	ret = request_percpu_irq(irq, sri_handler, "ARM-FFA-SRI", irq_pcpu);
+	if (drv_info->irq_is_npi)
+		ret = request_percpu_irq(drv_info->sr_or_np_irq, npi_handler,
+					 "ARM-FFA-NPI", irq_pcpu);
+	else
+		ret = request_percpu_irq(drv_info->sr_or_np_irq, sri_handler,
+					 "ARM-FFA-SRI", irq_pcpu);
 	if (ret) {
-		pr_err("Error registering notification IRQ %d: %d\n", irq, ret);
+		pr_err("Error registering NPI/SRI IRQ %d: %d\n",
+		       drv_info->sr_or_np_irq, ret);
 		return ret;
 	}
 
@@ -1453,7 +1478,7 @@  static void ffa_notifications_setup(void)
 		drv_info->bitmap_created = true;
 	}
 
-	irq = ffa_sr_or_np_irq_map();
+	irq = ffa_sr_or_np_irq_map(&drv_info->irq_is_npi);
 	if (irq <= 0) {
 		ret = irq;
 		goto cleanup;
@@ -1461,7 +1486,7 @@  static void ffa_notifications_setup(void)
 
 	drv_info->sr_or_np_irq = irq;
 
-	ret = ffa_init_pcpu_irq(irq);
+	ret = ffa_init_pcpu_irq();
 	if (ret)
 		goto cleanup;