On Thu, Feb 23, 2017 at 01:03:57PM +1100, Jonathan Gray wrote:
> On Wed, Feb 22, 2017 at 06:45:52PM -0500, Dale Rahn wrote:
> > Add psci 2.0 features to spin up/down/suspend processors.
> > 
> > This change uses extern weak symbols to determine if the platform supports
> > the cpu_on/cpu_off/cpu_suspend features. If available, it saves the fdt
> > provided argument values.
> > 
> > Some PSCI calls will return an int status, so the callfn has been updated
> > to return that status (eg cpu_on fail)
> > 
> > diff --git a/sys/dev/fdt/psci.c b/sys/dev/fdt/psci.c
> > index fceafd0e9ba..3177ff06beb 100644
> > --- a/sys/dev/fdt/psci.c
> > +++ b/sys/dev/fdt/psci.c
> > @@ -29,12 +29,19 @@
> >  extern void (*cpuresetfn)(void);
> >  extern void (*powerdownfn)(void);
> >  
> > +extern int (*cpu_suspend_fn)(void) __attribute__((weak)) ;
> > +extern int (*cpu_off_fn)(void) __attribute__((weak)) ;
> > +extern int (*cpu_on_fn)(uint64_t, uint64_t) __attribute__((weak)) ;
> > +
> >  #define SYSTEM_OFF 0x84000008
> >  #define SYSTEM_RESET       0x84000009
> >  
> >  struct psci_softc {
> >     struct device            sc_dev;
> > -   void                     (*callfn)(uint32_t, uint32_t, uint32_t, 
> > uint32_t);
> > +   int                      (*callfn)(uint32_t, uint32_t, uint32_t, 
> > uint32_t);
> > +   int sc_cpu_on;
> > +   int sc_cpu_off;
> > +   int sc_cpu_suspend;
> >  };
> 
> spacing is out here
> 
> >  
> >  struct psci_softc *psci_sc;
> > @@ -43,9 +50,12 @@ int      psci_match(struct device *, void *, void *);
> >  void       psci_attach(struct device *, struct device *, void *);
> >  void       psci_reset(void);
> >  void       psci_powerdown(void);
> > +int        psci_cpu_suspend(void);
> > +int        psci_cpu_off(void);
> > +int        psci_cpu_on(uint64_t, uint64_t);
> >  
> > -extern void hvc_call(uint32_t, uint32_t, uint32_t, uint32_t);
> > -extern void smc_call(uint32_t, uint32_t, uint32_t, uint32_t);
> > +extern int hvc_call(uint32_t, uint32_t, uint32_t, uint32_t);
> > +extern int smc_call(uint32_t, uint32_t, uint32_t, uint32_t);
> >  
> >  struct cfattach psci_ca = {
> >     sizeof(struct psci_softc), psci_match, psci_attach
> > @@ -83,6 +93,24 @@ psci_attach(struct device *parent, struct device *self, 
> > void *aux)
> >     psci_sc = sc;
> >     cpuresetfn = psci_reset;
> >     powerdownfn = psci_powerdown;
> > +
> > +   if (&cpu_suspend_fn != NULL) {
> > +           sc->sc_cpu_suspend = OF_getpropint(faa->fa_node, "cpu_suspend", 
> > 0);
> > +           if (sc->sc_cpu_suspend != 0)
> > +                   cpu_suspend_fn = psci_cpu_suspend;
> > +   }
> > +
> > +   if (&cpu_on_fn != NULL) {
> > +           sc->sc_cpu_on = OF_getpropint(faa->fa_node, "cpu_on", 0);
> > +           if (sc->sc_cpu_on != 0)
> > +                   cpu_on_fn = psci_cpu_on;
> > +   }
> > +
> > +   if (&cpu_off_fn != NULL) {
> > +           sc->sc_cpu_off = OF_getpropint(faa->fa_node, "cpu_off", 0);
> > +           if (sc->sc_cpu_off != 0)
> > +                   cpu_off_fn = psci_cpu_off;
> > +   }
> >  }
> 
> Can these nodes be relied on as being present?
> 
> Outside of qemu -M virt
> 
>     psci {
>         migrate = <0x84000005>;
>         cpu_on = <0x84000003>;
>         cpu_off = <0x84000002>;
>         cpu_suspend = <0x84000001>;
>         method = "hvc";
>         compatible = "arm,psci-0.2", "arm,psci";
>     };
> 
> I can only find
> 
> arm/boot/dts/artpec6.dtsi:              cpu_on = <0x84000003>;
> arm/boot/dts/ecx-common.dtsi:           cpu_on          = <0x84000006>;
> arm/boot/dts/keystone.dtsi:             cpu_on          = <0x84000003>;
> arm/boot/dts/xenvm-4.2.dts:             cpu_on          = <2>;
> arm64/boot/dts/al/alpine-v2.dtsi:               cpu_on = <0x84000003>;
> arm64/boot/dts/exynos/exynos5433.dtsi:          cpu_on = <0xC4000003>;
> arm64/boot/dts/lg/lg1312.dtsi:          cpu_on = <0x84000003>;
> arm64/boot/dts/lg/lg1313.dtsi:          cpu_on = <0x84000003>;
> arm64/boot/dts/mediatek/mt8173.dtsi:            cpu_on        = <0x84000003>;
> arm64/boot/dts/sprd/sc9836.dtsi:                cpu_on          = 
> <0xc4000003>;
> 
> 0x84000003 is SMC32, 0xC4000003 is SMC64 and there is actually
> a different calling convention for these...
> 
> The existing SYSTEM_OFF and SYSTEM_RESET uses are fine as they are just
> a 32 bit function id with no arguments.  But these new functions
> need to care about the arguments.
> 
> There is also PSCI_FEATURES in PSCI 1.0 that tests if function ids are
> supported.
> 

Updated diff, this has changed a bit since the psci driver has changed.

diff --git a/sys/dev/fdt/psci.c b/sys/dev/fdt/psci.c
index b24613a275c..2ba500ea718 100644
--- a/sys/dev/fdt/psci.c
+++ b/sys/dev/fdt/psci.c
@@ -29,14 +29,18 @@
 extern void (*cpuresetfn)(void);
 extern void (*powerdownfn)(void);
 
+extern int (*cpu_on_fn)(uint64_t, uint64_t) __attribute__((weak)) ;
+
 #define SYSTEM_OFF     0x84000008
 #define SYSTEM_RESET   0x84000009
+#define SYSTEM_CPU_ON64        0xC4000003
 
 struct psci_softc {
        struct device            sc_dev;
-       void                     (*callfn)(uint32_t, uint32_t, uint32_t, 
uint32_t);
+       int                      (*callfn)(uint32_t, uint32_t, uint32_t, 
uint32_t);
        int                      sc_system_off;
        int                      sc_system_reset;
+       int                      sc_system_on;
 };
 
 struct psci_softc *psci_sc;
@@ -45,9 +49,10 @@ int  psci_match(struct device *, void *, void *);
 void   psci_attach(struct device *, struct device *, void *);
 void   psci_reset(void);
 void   psci_powerdown(void);
+int    psci_cpu_on(uint64_t, uint64_t);
 
-extern void hvc_call(uint32_t, uint32_t, uint32_t, uint32_t);
-extern void smc_call(uint32_t, uint32_t, uint32_t, uint32_t);
+extern int hvc_call(uint32_t, uint32_t, uint32_t, uint32_t);
+extern int smc_call(uint32_t, uint32_t, uint32_t, uint32_t);
 
 struct cfattach psci_ca = {
        sizeof(struct psci_softc), psci_match, psci_attach
@@ -90,11 +95,13 @@ psci_attach(struct device *parent, struct device *self, 
void *aux)
            OF_is_compatible(faa->fa_node, "arm,psci-1.0")) {
                sc->sc_system_off = SYSTEM_OFF;
                sc->sc_system_reset = SYSTEM_RESET;
+               sc->sc_system_on = OF_getpropint(faa->fa_node, "cpu_on", 0);
        } else if (OF_is_compatible(faa->fa_node, "arm,psci")) {
                sc->sc_system_off = OF_getpropint(faa->fa_node,
                    "system_off", 0);
                sc->sc_system_reset = OF_getpropint(faa->fa_node,
                    "system_reset", 0);
+               sc->sc_system_on = OF_getpropint(faa->fa_node, "cpu_on", 0);
        }
 
        printf("\n");
@@ -104,6 +111,10 @@ psci_attach(struct device *parent, struct device *self, 
void *aux)
                powerdownfn = psci_powerdown;
        if (sc->sc_system_reset != 0)
                cpuresetfn = psci_reset;
+
+       if ((&cpu_on_fn != NULL) && (sc->sc_system_on == SYSTEM_CPU_ON64)) {
+               cpu_on_fn = psci_cpu_on;
+       }
 }
 
 void
@@ -121,3 +132,12 @@ psci_powerdown(void)
        if (sc->callfn)
                (*sc->callfn)(sc->sc_system_off, 0, 0, 0);
 }
+
+int
+psci_cpu_on(uint64_t mpidr, uint64_t pc)
+{
+       struct psci_softc *sc = psci_sc;
+       if (sc->callfn)
+               return (*sc->callfn)(sc->sc_system_on, mpidr, pc, 0);
+       return -1;
+}


Dale Rahn                               dr...@dalerahn.com

Reply via email to