@@ -315,6 +315,43 @@ static int sys_off_notify(struct notifier_block *nb,
315
315
return handler -> sys_off_cb (& data );
316
316
}
317
317
318
+ static struct sys_off_handler platform_sys_off_handler ;
319
+
320
+ static struct sys_off_handler * alloc_sys_off_handler (int priority )
321
+ {
322
+ struct sys_off_handler * handler ;
323
+ gfp_t flags ;
324
+
325
+ /*
326
+ * Platforms like m68k can't allocate sys_off handler dynamically
327
+ * at the early boot time because memory allocator isn't available yet.
328
+ */
329
+ if (priority == SYS_OFF_PRIO_PLATFORM ) {
330
+ handler = & platform_sys_off_handler ;
331
+ if (handler -> cb_data )
332
+ return ERR_PTR (- EBUSY );
333
+ } else {
334
+ if (system_state > SYSTEM_RUNNING )
335
+ flags = GFP_ATOMIC ;
336
+ else
337
+ flags = GFP_KERNEL ;
338
+
339
+ handler = kzalloc (sizeof (* handler ), flags );
340
+ if (!handler )
341
+ return ERR_PTR (- ENOMEM );
342
+ }
343
+
344
+ return handler ;
345
+ }
346
+
347
+ static void free_sys_off_handler (struct sys_off_handler * handler )
348
+ {
349
+ if (handler == & platform_sys_off_handler )
350
+ memset (handler , 0 , sizeof (* handler ));
351
+ else
352
+ kfree (handler );
353
+ }
354
+
318
355
/**
319
356
* register_sys_off_handler - Register sys-off handler
320
357
* @mode: Sys-off mode
@@ -345,9 +382,9 @@ register_sys_off_handler(enum sys_off_mode mode,
345
382
struct sys_off_handler * handler ;
346
383
int err ;
347
384
348
- handler = kzalloc ( sizeof ( * handler ), GFP_KERNEL );
349
- if (! handler )
350
- return ERR_PTR ( - ENOMEM ) ;
385
+ handler = alloc_sys_off_handler ( priority );
386
+ if (IS_ERR ( handler ) )
387
+ return handler ;
351
388
352
389
switch (mode ) {
353
390
case SYS_OFF_MODE_POWER_OFF_PREPARE :
@@ -364,7 +401,7 @@ register_sys_off_handler(enum sys_off_mode mode,
364
401
break ;
365
402
366
403
default :
367
- kfree (handler );
404
+ free_sys_off_handler (handler );
368
405
return ERR_PTR (- EINVAL );
369
406
}
370
407
@@ -391,7 +428,7 @@ register_sys_off_handler(enum sys_off_mode mode,
391
428
}
392
429
393
430
if (err ) {
394
- kfree (handler );
431
+ free_sys_off_handler (handler );
395
432
return ERR_PTR (err );
396
433
}
397
434
@@ -409,7 +446,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler)
409
446
{
410
447
int err ;
411
448
412
- if (! handler )
449
+ if (IS_ERR_OR_NULL ( handler ) )
413
450
return ;
414
451
415
452
if (handler -> blocking )
@@ -422,7 +459,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler)
422
459
/* sanity check, shall never happen */
423
460
WARN_ON (err );
424
461
425
- kfree (handler );
462
+ free_sys_off_handler (handler );
426
463
}
427
464
EXPORT_SYMBOL_GPL (unregister_sys_off_handler );
428
465
@@ -584,7 +621,23 @@ static void do_kernel_power_off_prepare(void)
584
621
*/
585
622
void do_kernel_power_off (void )
586
623
{
624
+ struct sys_off_handler * sys_off = NULL ;
625
+
626
+ /*
627
+ * Register sys-off handlers for legacy PM callback. This allows
628
+ * legacy PM callbacks temporary co-exist with the new sys-off API.
629
+ *
630
+ * TODO: Remove legacy handlers once all legacy PM users will be
631
+ * switched to the sys-off based APIs.
632
+ */
633
+ if (pm_power_off )
634
+ sys_off = register_sys_off_handler (SYS_OFF_MODE_POWER_OFF ,
635
+ SYS_OFF_PRIO_DEFAULT ,
636
+ legacy_pm_power_off , NULL );
637
+
587
638
atomic_notifier_call_chain (& power_off_handler_list , 0 , NULL );
639
+
640
+ unregister_sys_off_handler (sys_off );
588
641
}
589
642
590
643
/**
@@ -595,7 +648,8 @@ void do_kernel_power_off(void)
595
648
*/
596
649
bool kernel_can_power_off (void )
597
650
{
598
- return !atomic_notifier_call_chain_is_empty (& power_off_handler_list );
651
+ return !atomic_notifier_call_chain_is_empty (& power_off_handler_list ) ||
652
+ pm_power_off ;
599
653
}
600
654
EXPORT_SYMBOL_GPL (kernel_can_power_off );
601
655
@@ -630,7 +684,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
630
684
void __user * , arg )
631
685
{
632
686
struct pid_namespace * pid_ns = task_active_pid_ns (current );
633
- struct sys_off_handler * sys_off = NULL ;
634
687
char buffer [256 ];
635
688
int ret = 0 ;
636
689
@@ -655,21 +708,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
655
708
if (ret )
656
709
return ret ;
657
710
658
- /*
659
- * Register sys-off handlers for legacy PM callback. This allows
660
- * legacy PM callbacks temporary co-exist with the new sys-off API.
661
- *
662
- * TODO: Remove legacy handlers once all legacy PM users will be
663
- * switched to the sys-off based APIs.
664
- */
665
- if (pm_power_off ) {
666
- sys_off = register_sys_off_handler (SYS_OFF_MODE_POWER_OFF ,
667
- SYS_OFF_PRIO_DEFAULT ,
668
- legacy_pm_power_off , NULL );
669
- if (IS_ERR (sys_off ))
670
- return PTR_ERR (sys_off );
671
- }
672
-
673
711
/* Instead of trying to make the power_off code look like
674
712
* halt when pm_power_off is not set do it the easy way.
675
713
*/
@@ -727,7 +765,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
727
765
break ;
728
766
}
729
767
mutex_unlock (& system_transition_mutex );
730
- unregister_sys_off_handler (sys_off );
731
768
return ret ;
732
769
}
733
770
0 commit comments