diff mbox

[2/4] arm: add a function to invoke the PSCI handler and use it

Message ID 1385380964-22230-3-git-send-email-andre.przywara@linaro.org
State New
Headers show

Commit Message

Andre Przywara Nov. 25, 2013, 12:02 p.m. UTC
The PSCI handler is invoked via a secure monitor call with the
arguments defined in registers [1]. Copy the function from the
Linux code and adjust it to work on both ARM32 and ARM64.
Later use that function instead of the generic GIC SEV kick to
actually bring up the secondary CPUs.

[1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0022b/index.html

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
 xen/arch/arm/arm32/smpboot.c |  1 -
 xen/arch/arm/smpboot.c       | 39 +++++++++++++++++++++++++++++++++++----
 2 files changed, 35 insertions(+), 5 deletions(-)

Comments

Ian Campbell Nov. 26, 2013, 11:18 a.m. UTC | #1
On Mon, 2013-11-25 at 13:02 +0100, Andre Przywara wrote:
> The PSCI handler is invoked via a secure monitor call with the
> arguments defined in registers [1]. Copy the function from the
> Linux code and adjust it to work on both ARM32 and ARM64.
> Later use that function instead of the generic GIC SEV kick to
> actually bring up the secondary CPUs.
> 
> [1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0022b/index.html
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
>  xen/arch/arm/arm32/smpboot.c |  1 -
>  xen/arch/arm/smpboot.c       | 39 +++++++++++++++++++++++++++++++++++----
>  2 files changed, 35 insertions(+), 5 deletions(-)
> 
> diff --git a/xen/arch/arm/arm32/smpboot.c b/xen/arch/arm/arm32/smpboot.c
> index 88fe8fb..fcf653f 100644
> --- a/xen/arch/arm/arm32/smpboot.c
> +++ b/xen/arch/arm/arm32/smpboot.c
> @@ -10,7 +10,6 @@ int __init arch_smp_init(void)
>  
>  int __init arch_cpu_init(int cpu, struct dt_device_node *dn)
>  {
> -    /* TODO handle PSCI init */
>      return 0;
>  }
>  
> diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
> index 97bd414..44326d8 100644
> --- a/xen/arch/arm/smpboot.c
> +++ b/xen/arch/arm/smpboot.c
> @@ -89,6 +89,29 @@ smp_clear_cpu_maps (void)
>      cpu_logical_map(0) = READ_SYSREG(MPIDR_EL1) & MPIDR_HWID_MASK;
>  }
>  
> +#ifdef CONFIG_ARM_32
> +#define REG_PREFIX "r"
> +#else
> +#define REG_PREFIX "x"
> +#endif
> +
> +static noinline int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1,
> +                                         u32 arg2)

Please can you put this in psci.c and provide wrappers e.g.
psci_cpu_up(). THese can return some suitable errno if PSCI isn't
enabled. Or we could add a psci_enabled() call

Why noinline?

> +{
> +    asm volatile(
> +        __asmeq("%0", REG_PREFIX"0")
> +        __asmeq("%1", REG_PREFIX"1")
> +        __asmeq("%2", REG_PREFIX"2")
> +        __asmeq("%3", REG_PREFIX"3")
> +        "smc #0"
> +        : "+r" (function_id)
> +        : "r" (arg0), "r" (arg1), "r" (arg2));
> +
> +    return function_id;
> +}
> +
> +#undef REG_PREFIX
> +
>  uint32_t psci_host_cpu_on_nr;
>  
>  static int __init psci_host_init(void)
> @@ -393,10 +416,18 @@ int __cpu_up(unsigned int cpu)
>          return rc;
>      }
>  
> -    /* We don't know the GIC ID of the CPU until it has woken up, so just signal
> -     * everyone and rely on our own smp_up_cpu gate to ensure only the one we
> -     * want gets through. */
> -    send_SGI_allbutself(GIC_SGI_EVENT_CHECK);
> +    if ( psci_host_cpu_on_nr != 0 )

We could go for a set of smp function pointers initialised by
psci_init() but I think for now 
	if (psci_cpu_up(cpu, __pa(...)) < 0)
	{
	    /* No PSCI, send a manual ... blah. We don't know the GIC
             * ID, etc etc
             */
            send_SGI...(...)
	}
would be OK? Or could use a psci_enable() call, I have slightly less
preference for that.

> +    {
> +        /* If the DTB provided a PSCI node, use this for kicking the CPUs */
> +        __invoke_psci_fn_smc(
> +            psci_host_cpu_on_nr, cpu, __pa(init_secondary), 0);
> +    } else
> +    {
> +        /* We don't know the GIC ID of the CPU until it has woken up, so just
> +         * signal everyone and rely on our own smp_up_cpu gate to ensure only
> +         * the one we want gets through. */
> +        send_SGI_allbutself(GIC_SGI_EVENT_CHECK);
> +    }
>  
>      while ( !cpu_online(cpu) )
>      {
Andre Przywara Nov. 28, 2013, 10:59 a.m. UTC | #2
On 11/26/2013 12:18 PM, Ian Campbell wrote:
> On Mon, 2013-11-25 at 13:02 +0100, Andre Przywara wrote:
>> The PSCI handler is invoked via a secure monitor call with the
>> arguments defined in registers [1]. Copy the function from the
>> Linux code and adjust it to work on both ARM32 and ARM64.
>> Later use that function instead of the generic GIC SEV kick to
>> actually bring up the secondary CPUs.
>>
>> [1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0022b/index.html
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>>   xen/arch/arm/arm32/smpboot.c |  1 -
>>   xen/arch/arm/smpboot.c       | 39 +++++++++++++++++++++++++++++++++++----
>>   2 files changed, 35 insertions(+), 5 deletions(-)
>>
>> diff --git a/xen/arch/arm/arm32/smpboot.c b/xen/arch/arm/arm32/smpboot.c
>> index 88fe8fb..fcf653f 100644
>> --- a/xen/arch/arm/arm32/smpboot.c
>> +++ b/xen/arch/arm/arm32/smpboot.c
>> @@ -10,7 +10,6 @@ int __init arch_smp_init(void)
>>
>>   int __init arch_cpu_init(int cpu, struct dt_device_node *dn)
>>   {
>> -    /* TODO handle PSCI init */
>>       return 0;
>>   }
>>
>> diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
>> index 97bd414..44326d8 100644
>> --- a/xen/arch/arm/smpboot.c
>> +++ b/xen/arch/arm/smpboot.c
>> @@ -89,6 +89,29 @@ smp_clear_cpu_maps (void)
>>       cpu_logical_map(0) = READ_SYSREG(MPIDR_EL1) & MPIDR_HWID_MASK;
>>   }
>>
>> +#ifdef CONFIG_ARM_32
>> +#define REG_PREFIX "r"
>> +#else
>> +#define REG_PREFIX "x"
>> +#endif
>> +
>> +static noinline int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1,
>> +                                         u32 arg2)
>
> Please can you put this in psci.c and provide wrappers e.g.
> psci_cpu_up(). THese can return some suitable errno if PSCI isn't
> enabled. Or we could add a psci_enabled() call
>
> Why noinline?

This was copied from Linux and I thought it was there for a reason, so I 
kept it. But looking closer this was to make sure Linux can use function 
pointers later (to abstract hvc and smc calling), so we can remove this 
for Xen.

Regards,
Andre.
diff mbox

Patch

diff --git a/xen/arch/arm/arm32/smpboot.c b/xen/arch/arm/arm32/smpboot.c
index 88fe8fb..fcf653f 100644
--- a/xen/arch/arm/arm32/smpboot.c
+++ b/xen/arch/arm/arm32/smpboot.c
@@ -10,7 +10,6 @@  int __init arch_smp_init(void)
 
 int __init arch_cpu_init(int cpu, struct dt_device_node *dn)
 {
-    /* TODO handle PSCI init */
     return 0;
 }
 
diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
index 97bd414..44326d8 100644
--- a/xen/arch/arm/smpboot.c
+++ b/xen/arch/arm/smpboot.c
@@ -89,6 +89,29 @@  smp_clear_cpu_maps (void)
     cpu_logical_map(0) = READ_SYSREG(MPIDR_EL1) & MPIDR_HWID_MASK;
 }
 
+#ifdef CONFIG_ARM_32
+#define REG_PREFIX "r"
+#else
+#define REG_PREFIX "x"
+#endif
+
+static noinline int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1,
+                                         u32 arg2)
+{
+    asm volatile(
+        __asmeq("%0", REG_PREFIX"0")
+        __asmeq("%1", REG_PREFIX"1")
+        __asmeq("%2", REG_PREFIX"2")
+        __asmeq("%3", REG_PREFIX"3")
+        "smc #0"
+        : "+r" (function_id)
+        : "r" (arg0), "r" (arg1), "r" (arg2));
+
+    return function_id;
+}
+
+#undef REG_PREFIX
+
 uint32_t psci_host_cpu_on_nr;
 
 static int __init psci_host_init(void)
@@ -393,10 +416,18 @@  int __cpu_up(unsigned int cpu)
         return rc;
     }
 
-    /* We don't know the GIC ID of the CPU until it has woken up, so just signal
-     * everyone and rely on our own smp_up_cpu gate to ensure only the one we
-     * want gets through. */
-    send_SGI_allbutself(GIC_SGI_EVENT_CHECK);
+    if ( psci_host_cpu_on_nr != 0 )
+    {
+        /* If the DTB provided a PSCI node, use this for kicking the CPUs */
+        __invoke_psci_fn_smc(
+            psci_host_cpu_on_nr, cpu, __pa(init_secondary), 0);
+    } else
+    {
+        /* We don't know the GIC ID of the CPU until it has woken up, so just
+         * signal everyone and rely on our own smp_up_cpu gate to ensure only
+         * the one we want gets through. */
+        send_SGI_allbutself(GIC_SGI_EVENT_CHECK);
+    }
 
     while ( !cpu_online(cpu) )
     {