@@ -36,7 +36,10 @@ u8 *secondary_stacks[MAX_CPUS] = {dummy_stack};
3636static bool wfe_mode = false;
3737
3838static int target_cpu ;
39+ static int cpu_nodes [MAX_CPUS ];
3940static struct spin_table spin_table [MAX_CPUS ];
41+ static u64 pmgr_reg ;
42+ static u64 cpu_start_off ;
4043
4144extern u8 _vectors_start [0 ];
4245
@@ -79,7 +82,7 @@ void smp_secondary_entry(void)
7982 }
8083}
8184
82- static void smp_start_cpu (int index , int die , int cluster , int core , u64 rvbar , u64 cpu_start_base )
85+ static void smp_start_cpu (int index , int die , int cluster , int core , u64 impl , u64 cpu_start_base )
8386{
8487 int i ;
8588
@@ -99,7 +102,7 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 rvbar,
99102
100103 sysop ("dmb sy" );
101104
102- write64 (rvbar , (u64 )_vectors_start );
105+ write64 (impl , (u64 )_vectors_start );
103106
104107 cpu_start_base += die * PMGR_DIE_OFFSET ;
105108
@@ -110,27 +113,73 @@ static void smp_start_cpu(int index, int die, int cluster, int core, u64 rvbar,
110113 // Actually start the core
111114 write32 (cpu_start_base + 0x8 + 4 * cluster , 1 << core );
112115
113- for (i = 0 ; i < 500 ; i ++ ) {
116+ for (i = 0 ; i < 100 ; i ++ ) {
114117 sysop ("dmb ld" );
115118 if (spin_table [index ].flag )
116119 break ;
117120 udelay (1000 );
118121 }
119122
120- if (i >= 500 )
123+ if (i >= 100 )
121124 printf ("Failed!\n" );
122125 else
123126 printf (" Started.\n" );
124127
125128 _reset_stack = dummy_stack + DUMMY_STACK_SIZE ;
126129}
127130
131+ static void smp_stop_cpu (int index , int die , int cluster , int core , u64 impl , u64 cpu_start_base ,
132+ bool deep_sleep )
133+ {
134+ int i ;
135+
136+ if (index >= MAX_CPUS )
137+ return ;
138+
139+ if (!spin_table [index ].flag )
140+ return ;
141+
142+ printf ("Stopping CPU %d (%d:%d:%d)... " , index , die , cluster , core );
143+
144+ cpu_start_base += die * PMGR_DIE_OFFSET ;
145+
146+ // Request CPU stop
147+ write32 (cpu_start_base + 0x0 , 1 << (4 * cluster + core ));
148+
149+ // Put the CPU to sleep
150+ smp_call1 (index , cpu_sleep , deep_sleep );
151+
152+ // If going into deep sleep, powering off the last core in a cluster kills our register
153+ // access, so just wait a bit.
154+ if (deep_sleep ) {
155+ udelay (10000 );
156+ printf (" Presumed stopped.\n" );
157+ memset (& spin_table [index ], 0 , sizeof (struct spin_table ));
158+ return ;
159+ }
160+
161+ // Check that it actually shut down
162+ for (i = 0 ; i < 50 ; i ++ ) {
163+ sysop ("dmb ld" );
164+ if (!(read64 (impl + 0x100 ) & 0xff ))
165+ break ;
166+ udelay (1000 );
167+ }
168+
169+ if (i >= 50 ) {
170+ printf ("Failed!\n" );
171+ } else {
172+ printf (" Stopped.\n" );
173+
174+ memset (& spin_table [index ], 0 , sizeof (struct spin_table ));
175+ }
176+ }
177+
128178void smp_start_secondaries (void )
129179{
130180 printf ("Starting secondary CPUs...\n" );
131181
132182 int pmgr_path [8 ];
133- u64 pmgr_reg ;
134183
135184 if (adt_path_offset_trace (adt , "/arm-io/pmgr" , pmgr_path ) < 0 ) {
136185 printf ("Error getting /arm-io/pmgr node\n" );
@@ -147,9 +196,6 @@ void smp_start_secondaries(void)
147196 return ;
148197 }
149198
150- int cpu_nodes [MAX_CPUS ];
151- u64 cpu_start_off ;
152-
153199 memset (cpu_nodes , 0 , sizeof (cpu_nodes ));
154200
155201 switch (chip_id ) {
@@ -208,6 +254,32 @@ void smp_start_secondaries(void)
208254 spin_table [0 ].mpidr = mrs (MPIDR_EL1 ) & 0xFFFFFF ;
209255}
210256
257+ void smp_stop_secondaries (bool deep_sleep )
258+ {
259+ printf ("Stopping secondary CPUs...\n" );
260+ smp_set_wfe_mode (true);
261+
262+ for (int i = 1 ; i < MAX_CPUS ; i ++ ) {
263+ int node = cpu_nodes [i ];
264+
265+ if (!node )
266+ continue ;
267+
268+ u32 reg ;
269+ u64 cpu_impl_reg [2 ];
270+ if (ADT_GETPROP (adt , node , "reg" , & reg ) < 0 )
271+ continue ;
272+ if (ADT_GETPROP_ARRAY (adt , node , "cpu-impl-reg" , cpu_impl_reg ) < 0 )
273+ continue ;
274+
275+ u8 core = FIELD_GET (CPU_REG_CORE , reg );
276+ u8 cluster = FIELD_GET (CPU_REG_CLUSTER , reg );
277+ u8 die = FIELD_GET (CPU_REG_DIE , reg );
278+
279+ smp_stop_cpu (i , die , cluster , core , cpu_impl_reg [0 ], pmgr_reg + cpu_start_off , deep_sleep );
280+ }
281+ }
282+
211283void smp_send_ipi (int cpu )
212284{
213285 if (cpu >= MAX_CPUS )
0 commit comments