Merge back reboot/poweroff notifiers rework for 5.19-rc1.
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 25 May 2022 12:38:29 +0000 (14:38 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 25 May 2022 12:38:29 +0000 (14:38 +0200)
1  2 
arch/arm64/kernel/process.c
arch/m68k/kernel/setup_mm.c
arch/x86/xen/enlighten_pv.c
drivers/acpi/sleep.c
drivers/regulator/pfuze100-regulator.c
include/linux/pm.h

@@@ -111,8 -111,7 +111,7 @@@ void machine_power_off(void
  {
        local_irq_disable();
        smp_send_stop();
-       if (pm_power_off)
-               pm_power_off();
+       do_kernel_power_off();
  }
  
  /*
@@@ -250,8 -249,6 +249,8 @@@ void show_regs(struct pt_regs *regs
  static void tls_thread_flush(void)
  {
        write_sysreg(0, tpidr_el0);
 +      if (system_supports_tpidr2())
 +              write_sysreg_s(0, SYS_TPIDR2_EL0);
  
        if (is_compat_task()) {
                current->thread.uw.tp_value = 0;
@@@ -300,42 -297,16 +299,42 @@@ int arch_dup_task_struct(struct task_st
  
        /*
         * Detach src's sve_state (if any) from dst so that it does not
 -       * get erroneously used or freed prematurely.  dst's sve_state
 +       * get erroneously used or freed prematurely.  dst's copies
         * will be allocated on demand later on if dst uses SVE.
         * For consistency, also clear TIF_SVE here: this could be done
         * later in copy_process(), but to avoid tripping up future
 -       * maintainers it is best not to leave TIF_SVE and sve_state in
 +       * maintainers it is best not to leave TIF flags and buffers in
         * an inconsistent state, even temporarily.
         */
        dst->thread.sve_state = NULL;
        clear_tsk_thread_flag(dst, TIF_SVE);
  
 +      /*
 +       * In the unlikely event that we create a new thread with ZA
 +       * enabled we should retain the ZA state so duplicate it here.
 +       * This may be shortly freed if we exec() or if CLONE_SETTLS
 +       * but it's simpler to do it here. To avoid confusing the rest
 +       * of the code ensure that we have a sve_state allocated
 +       * whenever za_state is allocated.
 +       */
 +      if (thread_za_enabled(&src->thread)) {
 +              dst->thread.sve_state = kzalloc(sve_state_size(src),
 +                                              GFP_KERNEL);
 +              if (!dst->thread.sve_state)
 +                      return -ENOMEM;
 +              dst->thread.za_state = kmemdup(src->thread.za_state,
 +                                             za_state_size(src),
 +                                             GFP_KERNEL);
 +              if (!dst->thread.za_state) {
 +                      kfree(dst->thread.sve_state);
 +                      dst->thread.sve_state = NULL;
 +                      return -ENOMEM;
 +              }
 +      } else {
 +              dst->thread.za_state = NULL;
 +              clear_tsk_thread_flag(dst, TIF_SME);
 +      }
 +
        /* clear any pending asynchronous tag fault raised by the parent */
        clear_tsk_thread_flag(dst, TIF_MTE_ASYNC_FAULT);
  
@@@ -371,8 -342,6 +370,8 @@@ int copy_thread(unsigned long clone_fla
                 * out-of-sync with the saved value.
                 */
                *task_user_tls(p) = read_sysreg(tpidr_el0);
 +              if (system_supports_tpidr2())
 +                      p->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
  
                if (stack_start) {
                        if (is_compat_thread(task_thread_info(p)))
  
                /*
                 * If a TLS pointer was passed to clone, use it for the new
 -               * thread.
 +               * thread.  We also reset TPIDR2 if it's in use.
                 */
 -              if (clone_flags & CLONE_SETTLS)
 +              if (clone_flags & CLONE_SETTLS) {
                        p->thread.uw.tp_value = tls;
 +                      p->thread.tpidr2_el0 = 0;
 +              }
        } else {
                /*
                 * A kthread has no context to ERET to, so ensure any buggy
  void tls_preserve_current_state(void)
  {
        *task_user_tls(current) = read_sysreg(tpidr_el0);
 +      if (system_supports_tpidr2() && !is_compat_task())
 +              current->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
  }
  
  static void tls_thread_switch(struct task_struct *next)
                write_sysreg(0, tpidrro_el0);
  
        write_sysreg(*task_user_tls(next), tpidr_el0);
 +      if (system_supports_tpidr2())
 +              write_sysreg_s(next->thread.tpidr2_el0, SYS_TPIDR2_EL0);
  }
  
  /*
@@@ -98,7 -98,6 +98,6 @@@ EXPORT_SYMBOL(mach_get_rtc_pll)
  EXPORT_SYMBOL(mach_set_rtc_pll);
  void (*mach_reset)( void );
  void (*mach_halt)( void );
- void (*mach_power_off)( void );
  #ifdef CONFIG_HEARTBEAT
  void (*mach_heartbeat) (int);
  EXPORT_SYMBOL(mach_heartbeat);
@@@ -181,8 -180,6 +180,8 @@@ static void __init m68k_parse_bootinfo(
                                unknown = hp300_parse_bootinfo(record);
                        else if (MACH_IS_APOLLO)
                                unknown = apollo_parse_bootinfo(record);
 +                      else if (MACH_IS_VIRT)
 +                              unknown = virt_parse_bootinfo(record);
                        else
                                unknown = 1;
                }
@@@ -314,11 -311,6 +313,11 @@@ void __init setup_arch(char **cmdline_p
                config_BSP(NULL, 0);
                break;
  #endif
 +#ifdef CONFIG_VIRT
 +      case MACH_VIRT:
 +              config_virt();
 +              break;
 +#endif
        default:
                panic("No configuration setup");
        }
@@@ -30,6 -30,8 +30,7 @@@
  #include <linux/pci.h>
  #include <linux/gfp.h>
  #include <linux/edd.h>
 -#include <linux/objtool.h>
+ #include <linux/reboot.h>
  
  #include <xen/xen.h>
  #include <xen/events.h>
@@@ -164,6 -166,7 +165,6 @@@ static void xen_cpuid(unsigned int *ax
  
        *bx &= maskebx;
  }
 -STACK_FRAME_NON_STANDARD(xen_cpuid); /* XEN_EMULATE_PREFIX */
  
  static bool __init xen_check_mwait(void)
  {
@@@ -1069,8 -1072,7 +1070,7 @@@ static void xen_machine_halt(void
  
  static void xen_machine_power_off(void)
  {
-       if (pm_power_off)
-               pm_power_off();
+       do_kernel_power_off();
        xen_reboot(SHUTDOWN_poweroff);
  }
  
diff --combined drivers/acpi/sleep.c
@@@ -373,18 -373,6 +373,18 @@@ static const struct dmi_system_id acpis
                DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"),
                },
        },
 +      /*
 +       * ASUS B1400CEAE hangs on resume from suspend (see
 +       * https://bugzilla.kernel.org/show_bug.cgi?id=215742).
 +       */
 +      {
 +      .callback = init_default_s3,
 +      .ident = "ASUS B1400CEAE",
 +      .matches = {
 +              DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 +              DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK B1400CEAE"),
 +              },
 +      },
        {},
  };
  
@@@ -1035,20 -1023,22 +1035,22 @@@ static void acpi_sleep_hibernate_setup(
  static inline void acpi_sleep_hibernate_setup(void) {}
  #endif /* !CONFIG_HIBERNATION */
  
- static void acpi_power_off_prepare(void)
+ static int acpi_power_off_prepare(struct sys_off_data *data)
  {
        /* Prepare to power off the system */
        acpi_sleep_prepare(ACPI_STATE_S5);
        acpi_disable_all_gpes();
        acpi_os_wait_events_complete();
+       return NOTIFY_DONE;
  }
  
- static void acpi_power_off(void)
+ static int acpi_power_off(struct sys_off_data *data)
  {
        /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
        pr_debug("%s called\n", __func__);
        local_irq_disable();
        acpi_enter_sleep_state(ACPI_STATE_S5);
+       return NOTIFY_DONE;
  }
  
  int __init acpi_sleep_init(void)
  
        if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
                sleep_states[ACPI_STATE_S5] = 1;
-               pm_power_off_prepare = acpi_power_off_prepare;
-               pm_power_off = acpi_power_off;
+               register_sys_off_handler(SYS_OFF_MODE_POWER_OFF_PREPARE,
+                                        SYS_OFF_PRIO_FIRMWARE,
+                                        acpi_power_off_prepare, NULL);
+               register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+                                        SYS_OFF_PRIO_FIRMWARE,
+                                        acpi_power_off, NULL);
        } else {
                acpi_no_s5 = true;
        }
@@@ -10,6 -10,7 +10,7 @@@
  #include <linux/of_device.h>
  #include <linux/regulator/of_regulator.h>
  #include <linux/platform_device.h>
+ #include <linux/reboot.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/machine.h>
  #include <linux/regulator/pfuze100.h>
@@@ -521,7 -522,6 +522,7 @@@ static int pfuze_parse_regulators_dt(st
        parent = of_get_child_by_name(np, "regulators");
        if (!parent) {
                dev_err(dev, "regulators node not found\n");
 +              of_node_put(np);
                return -EINVAL;
        }
  
        }
  
        of_node_put(parent);
 +      of_node_put(np);
        if (ret < 0) {
                dev_err(dev, "Error parsing regulator init data: %d\n",
                        ret);
@@@ -571,10 -570,10 +572,10 @@@ static inline struct device_node *match
        return pfuze_matches[index].of_node;
  }
  
- static struct pfuze_chip *syspm_pfuze_chip;
- static void pfuze_power_off_prepare(void)
+ static int pfuze_power_off_prepare(struct sys_off_data *data)
  {
+       struct pfuze_chip *syspm_pfuze_chip = data->cb_data;
        dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
  
        /* Switch from default mode: APS/APS to APS/Off */
        regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL,
                           PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
                           PFUZE100_VGENxSTBY);
+       return NOTIFY_DONE;
  }
  
  static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
  {
+       int err;
        if (pfuze_chip->chip_id != PFUZE100) {
                dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n");
                return -ENODEV;
        }
  
-       if (pm_power_off_prepare) {
-               dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already registered.\n");
-               return -EBUSY;
+       err = devm_register_sys_off_handler(pfuze_chip->dev,
+                                           SYS_OFF_MODE_POWER_OFF_PREPARE,
+                                           SYS_OFF_PRIO_DEFAULT,
+                                           pfuze_power_off_prepare,
+                                           pfuze_chip);
+       if (err) {
+               dev_err(pfuze_chip->dev, "failed to register sys-off handler: %d\n",
+                       err);
+               return err;
        }
  
-       if (syspm_pfuze_chip) {
-               dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
-               return -EBUSY;
-       }
-       syspm_pfuze_chip = pfuze_chip;
-       pm_power_off_prepare = pfuze_power_off_prepare;
        return 0;
  }
  
@@@ -839,23 -840,12 +842,12 @@@ static int pfuze100_regulator_probe(str
        return 0;
  }
  
- static int pfuze100_regulator_remove(struct i2c_client *client)
- {
-       if (syspm_pfuze_chip) {
-               syspm_pfuze_chip = NULL;
-               pm_power_off_prepare = NULL;
-       }
-       return 0;
- }
  static struct i2c_driver pfuze_driver = {
        .driver = {
                .name = "pfuze100-regulator",
                .of_match_table = pfuze_dt_ids,
        },
        .probe = pfuze100_regulator_probe,
-       .remove = pfuze100_regulator_remove,
  };
  module_i2c_driver(pfuze_driver);
  
diff --combined include/linux/pm.h
@@@ -21,7 -21,6 +21,6 @@@
   * Callbacks for platform drivers to implement.
   */
  extern void (*pm_power_off)(void);
- extern void (*pm_power_off_prepare)(void);
  
  struct device; /* we have a circular dep with device.h */
  #ifdef CONFIG_VT_CONSOLE_SLEEP
@@@ -368,13 -367,13 +367,13 @@@ const struct dev_pm_ops name = { 
  
  #ifdef CONFIG_PM
  #define _EXPORT_DEV_PM_OPS(name, suspend_fn, resume_fn, runtime_suspend_fn, \
 -                         runtime_resume_fn, idle_fn, sec) \
 +                         runtime_resume_fn, idle_fn, sec, ns)         \
        _DEFINE_DEV_PM_OPS(name, suspend_fn, resume_fn, runtime_suspend_fn, \
                           runtime_resume_fn, idle_fn); \
 -      _EXPORT_SYMBOL(name, sec)
 +      __EXPORT_SYMBOL(name, sec, ns)
  #else
  #define _EXPORT_DEV_PM_OPS(name, suspend_fn, resume_fn, runtime_suspend_fn, \
 -                         runtime_resume_fn, idle_fn, sec) \
 +                         runtime_resume_fn, idle_fn, sec, ns) \
  static __maybe_unused _DEFINE_DEV_PM_OPS(__static_##name, suspend_fn, \
                                         resume_fn, runtime_suspend_fn, \
                                         runtime_resume_fn, idle_fn)
        _DEFINE_DEV_PM_OPS(name, suspend_fn, resume_fn, NULL, NULL, NULL)
  
  #define EXPORT_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
 -      _EXPORT_DEV_PM_OPS(name, suspend_fn, resume_fn, NULL, NULL, NULL, "")
 +      _EXPORT_DEV_PM_OPS(name, suspend_fn, resume_fn, NULL, NULL, NULL, "", "")
  #define EXPORT_GPL_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
 -      _EXPORT_DEV_PM_OPS(name, suspend_fn, resume_fn, NULL, NULL, NULL, "_gpl")
 +      _EXPORT_DEV_PM_OPS(name, suspend_fn, resume_fn, NULL, NULL, NULL, "_gpl", "")
 +#define EXPORT_NS_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn, ns)  \
 +      _EXPORT_DEV_PM_OPS(name, suspend_fn, resume_fn, NULL, NULL, NULL, "", #ns)
 +#define EXPORT_NS_GPL_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn, ns)      \
 +      _EXPORT_DEV_PM_OPS(name, suspend_fn, resume_fn, NULL, NULL, NULL, "_gpl", #ns)
  
  /* Deprecated. Use DEFINE_SIMPLE_DEV_PM_OPS() instead. */
  #define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \