Merge tag 'pm-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 2 Aug 2022 18:17:00 +0000 (11:17 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 2 Aug 2022 18:17:00 +0000 (11:17 -0700)
Pull power management updates from Rafael Wysocki:
 "These are mostly minor improvements all over including new CPU IDs for
  the Intel RAPL driver, an Energy Model rework to use micro-Watt as the
  power unit, cpufreq fixes and cleanus, cpuidle updates, devfreq
  updates, documentation cleanups and a new version of the pm-graph
  suite of utilities.

  Specifics:

   - Make cpufreq_show_cpus() more straightforward (Viresh Kumar).

   - Drop unnecessary CPU hotplug locking from store() used by cpufreq
     sysfs attributes (Viresh Kumar).

   - Make the ACPI cpufreq driver support the boost control interface on
     Zhaoxin/Centaur processors (Tony W Wang-oc).

   - Print a warning message on attempts to free an active cpufreq
     policy which should never happen (Viresh Kumar).

   - Fix grammar in the Kconfig help text for the loongson2 cpufreq
     driver (Randy Dunlap).

   - Use cpumask_var_t for an on-stack CPU mask in the ondemand cpufreq
     governor (Zhao Liu).

   - Add trace points for guest_halt_poll_ns grow/shrink to the haltpoll
     cpuidle driver (Eiichi Tsukata).

   - Modify intel_idle to treat C1 and C1E as independent idle states on
     Sapphire Rapids (Artem Bityutskiy).

   - Extend support for wakeirq to callback wrappers used during system
     suspend and resume (Ulf Hansson).

   - Defer waiting for device probe before loading a hibernation image
     till the first actual device access to avoid possible deadlocks
     reported by syzbot (Tetsuo Handa).

   - Unify device_init_wakeup() for PM_SLEEP and !PM_SLEEP (Bjorn
     Helgaas).

   - Add Raptor Lake-P to the list of processors supported by the Intel
     RAPL driver (George D Sworo).

   - Add Alder Lake-N and Raptor Lake-P to the list of processors for
     which Power Limit4 is supported in the Intel RAPL driver (Sumeet
     Pawnikar).

   - Make pm_genpd_remove() check genpd_debugfs_dir against NULL before
     attempting to remove it (Hsin-Yi Wang).

   - Change the Energy Model code to represent power in micro-Watts and
     adjust its users accordingly (Lukasz Luba).

   - Add new devfreq driver for Mediatek CCI (Cache Coherent
     Interconnect) (Johnson Wang).

   - Convert the Samsung Exynos SoC Bus bindings to DT schema of
     exynos-bus.c (Krzysztof Kozlowski).

   - Address kernel-doc warnings by adding the description for unused
     function parameters in devfreq core (Mauro Carvalho Chehab).

   - Use NULL to pass a null pointer rather than zero according to the
     function propotype in imx-bus.c (Colin Ian King).

   - Print error message instead of error interger value in
     tegra30-devfreq.c (Dmitry Osipenko).

   - Add checks to prevent setting negative frequency QoS limits for
     CPUs (Shivnandan Kumar).

   - Update the pm-graph suite of utilities to the latest revision 5.9
     including multiple improvements (Todd Brandt).

   - Drop pme_interrupt reference from the PCI power management
     documentation (Mario Limonciello)"

* tag 'pm-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (27 commits)
  powercap: RAPL: Add Power Limit4 support for Alder Lake-N and Raptor Lake-P
  PM: QoS: Add check to make sure CPU freq is non-negative
  PM: hibernate: defer device probing when resuming from hibernation
  intel_idle: make SPR C1 and C1E be independent
  cpufreq: ondemand: Use cpumask_var_t for on-stack cpu mask
  cpufreq: loongson2: fix Kconfig "its" grammar
  pm-graph v5.9
  cpufreq: Warn users while freeing active policy
  cpufreq: scmi: Support the power scale in micro-Watts in SCMI v3.1
  firmware: arm_scmi: Get detailed power scale from perf
  Documentation: EM: Switch to micro-Watts scale
  PM: EM: convert power field to micro-Watts precision and align drivers
  PM / devfreq: tegra30: Add error message for devm_devfreq_add_device()
  PM / devfreq: imx-bus: use NULL to pass a null pointer rather than zero
  PM / devfreq: shut up kernel-doc warnings
  dt-bindings: interconnect: samsung,exynos-bus: convert to dtschema
  PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  dt-bindings: interconnect: Add MediaTek CCI dt-bindings
  PM: domains: Ensure genpd_debugfs_dir exists before remove
  PM: runtime: Extend support for wakeirq for force_suspend|resume
  ...

1  2 
MAINTAINERS
drivers/firmware/arm_scmi/perf.c
drivers/idle/intel_idle.c
drivers/powercap/dtpm_cpu.c
drivers/thermal/cpufreq_cooling.c
include/linux/scmi_protocol.h

diff --combined MAINTAINERS
@@@ -242,11 -242,6 +242,11 @@@ F:       include/trace/events/9p.
  F:    include/uapi/linux/virtio_9p.h
  F:    net/9p/
  
 +A64FX DIAG DRIVER
 +M:    Hitomi Hasegawa <hasegawa-hitomi@fujitsu.com>
 +S:    Supported
 +F:    drivers/soc/fujitsu/a64fx-diag.c
 +
  A8293 MEDIA DRIVER
  M:    Antti Palosaari <crope@iki.fi>
  L:    linux-media@vger.kernel.org
@@@ -1899,7 -1894,6 +1899,7 @@@ L:      linux-aspeed@lists.ozlabs.org (moder
  S:    Supported
  Q:    https://patchwork.ozlabs.org/project/linux-aspeed/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/joel/aspeed.git
 +F:    Documentation/devicetree/bindings/arm/aspeed/
  F:    arch/arm/boot/dts/aspeed-*
  F:    arch/arm/mach-aspeed/
  N:    aspeed
@@@ -2147,13 -2141,11 +2147,13 @@@ M:   Jean-Marie Verdun <verdun@hpe.com
  M:    Nick Hawkins <nick.hawkins@hpe.com>
  S:    Maintained
  F:    Documentation/devicetree/bindings/arm/hpe,gxp.yaml
 +F:    Documentation/devicetree/bindings/spi/hpe,gxp-spi.yaml
  F:    Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
  F:    arch/arm/boot/dts/hpe-bmc*
  F:    arch/arm/boot/dts/hpe-gxp*
  F:    arch/arm/mach-hpe/
  F:    drivers/clocksource/timer-gxp.c
 +F:    drivers/spi/spi-gxp.c
  F:    drivers/watchdog/gxp-wdt.c
  
  ARM/IGEP MACHINE SUPPORT
@@@ -2457,11 -2449,9 +2457,11 @@@ F:    Documentation/devicetree/bindings/*/
  F:    Documentation/devicetree/bindings/arm/npcm/*
  F:    arch/arm/boot/dts/nuvoton-npcm*
  F:    arch/arm/mach-npcm/
 +F:    arch/arm64/boot/dts/nuvoton/
  F:    drivers/*/*npcm*
  F:    drivers/*/*/*npcm*
  F:    include/dt-bindings/clock/nuvoton,npcm7xx-clock.h
 +F:    include/dt-bindings/clock/nuvoton,npcm845-clk.h
  
  ARM/NUVOTON WPCM450 ARCHITECTURE
  M:    Jonathan Neuschäfer <j.neuschaefer@gmx.net>
@@@ -2626,8 -2616,6 +2626,8 @@@ Q:      http://patchwork.kernel.org/project/
  C:    irc://irc.libera.chat/renesas-soc
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
  F:    Documentation/devicetree/bindings/arm/renesas.yaml
 +F:    Documentation/devicetree/bindings/hwinfo/renesas,prr.yaml
 +F:    Documentation/devicetree/bindings/soc/renesas/
  F:    arch/arm64/boot/dts/renesas/
  F:    drivers/soc/renesas/
  F:    include/linux/soc/renesas/
@@@ -2746,7 -2734,6 +2746,7 @@@ Q:      http://patchwork.kernel.org/project/
  C:    irc://irc.libera.chat/renesas-soc
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
  F:    Documentation/devicetree/bindings/arm/renesas.yaml
 +F:    Documentation/devicetree/bindings/soc/renesas/
  F:    arch/arm/boot/dts/emev2*
  F:    arch/arm/boot/dts/gr-peach*
  F:    arch/arm/boot/dts/iwg20d-q7*
@@@ -2836,23 -2823,6 +2836,23 @@@ F:    drivers/clocksource/armv7m_systick.
  N:    stm32
  N:    stm
  
 +ARM/SUNPLUS SP7021 SOC SUPPORT
 +M:    Qin Jian <qinjian@cqplus1.com>
 +L:    linux-arm-kernel@lists.infradead.org (moderated for mon-subscribers)
 +S:    Maintained
 +W:    https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 +F:    Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 +F:    Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 +F:    Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 +F:    Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 +F:    arch/arm/boot/dts/sunplus-sp7021*.dts*
 +F:    arch/arm/configs/sp7021_*defconfig
 +F:    arch/arm/mach-sunplus/
 +F:    drivers/irqchip/irq-sp7021-intc.c
 +F:    drivers/reset/reset-sunplus.c
 +F:    include/dt-bindings/clock/sunplus,sp7021-clkc.h
 +F:    include/dt-bindings/reset/sunplus,sp7021-reset.h
 +
  ARM/Synaptics SoC support
  M:    Jisheng Zhang <jszhang@kernel.org>
  M:    Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@@@ -3905,28 -3875,15 +3905,28 @@@ BROADCOM BCMBCA ARM ARCHITECTUR
  M:    William Zhang <william.zhang@broadcom.com>
  M:    Anand Gore <anand.gore@broadcom.com>
  M:    Kursad Oney <kursad.oney@broadcom.com>
 +M:    Florian Fainelli <f.fainelli@gmail.com>
  R:    Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
  T:    git git://github.com/broadcom/stblinux.git
  F:    Documentation/devicetree/bindings/arm/bcm/brcm,bcmbca.yaml
 -F:    arch/arm/boot/dts/bcm47622.dtsi
 -F:    arch/arm/boot/dts/bcm947622.dts
 +F:    arch/arm64/boot/dts/broadcom/bcmbca/*
  N:    bcmbca
  N:    bcm[9]?47622
 +N:    bcm[9]?4912
 +N:    bcm[9]?63138
 +N:    bcm[9]?63146
 +N:    bcm[9]?63148
 +N:    bcm[9]?63158
 +N:    bcm[9]?63178
 +N:    bcm[9]?6756
 +N:    bcm[9]?6813
 +N:    bcm[9]?6846
 +N:    bcm[9]?6855
 +N:    bcm[9]?6856
 +N:    bcm[9]?6858
 +N:    bcm[9]?6878
  
  BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE
  M:    Florian Fainelli <f.fainelli@gmail.com>
@@@ -4002,6 -3959,14 +4002,6 @@@ S:     Maintaine
  F:    arch/arm/boot/dts/bcm47189*
  F:    arch/arm/boot/dts/bcm53573*
  
 -BROADCOM BCM63XX ARM ARCHITECTURE
 -M:    Florian Fainelli <f.fainelli@gmail.com>
 -R:    Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
 -L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 -S:    Maintained
 -T:    git git://github.com/broadcom/stblinux.git
 -N:    bcm63xx
 -
  BROADCOM BCM63XX/BCM33XX UDC DRIVER
  M:    Kevin Cernekee <cernekee@gmail.com>
  L:    linux-usb@vger.kernel.org
@@@ -4408,7 -4373,7 +4408,7 @@@ L:      linux-pm@vger.kernel.or
  L:    linux-samsung-soc@vger.kernel.org
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
- F:    Documentation/devicetree/bindings/devfreq/exynos-bus.txt
+ F:    Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml
  F:    drivers/devfreq/exynos-bus.c
  
  BUSLOGIC SCSI DRIVER
@@@ -5890,6 -5855,7 +5890,7 @@@ L:      linux-pm@vger.kernel.or
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
  F:    Documentation/devicetree/bindings/devfreq/
+ F:    Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
  F:    drivers/devfreq/
  F:    include/linux/devfreq.h
  F:    include/trace/events/devfreq.h
@@@ -7520,8 -7486,6 +7521,8 @@@ F:      include/video/s1d13xxxfb.
  EROFS FILE SYSTEM
  M:    Gao Xiang <xiang@kernel.org>
  M:    Chao Yu <chao@kernel.org>
 +R:    Yue Hu <huyue2@coolpad.com>
 +R:    Jeffle Xu <jefflexu@linux.alibaba.com>
  L:    linux-erofs@lists.ozlabs.org
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
@@@ -9073,12 -9037,6 +9074,12 @@@ F:    Documentation/admin-guide/perf/hisi-
  F:    Documentation/admin-guide/perf/hisi-pmu.rst
  F:    drivers/perf/hisilicon
  
 +HISILICON HNS3 PMU DRIVER
 +M:    Guangbin Huang <huangguangbin2@huawei.com>
 +S:    Supported
 +F:    Documentation/admin-guide/perf/hns3-pmu.rst
 +F:    drivers/perf/hisilicon/hns3_pmu.c
 +
  HISILICON QM AND ZIP Controller DRIVER
  M:    Zhou Wang <wangzhou1@hisilicon.com>
  L:    linux-crypto@vger.kernel.org
@@@ -9661,7 -9619,6 +9662,7 @@@ F:      drivers/input/misc/ideapad_slidebar.
  
  IDMAPPED MOUNTS
  M:    Christian Brauner <brauner@kernel.org>
 +M:    Seth Forshee <sforshee@kernel.org>
  L:    linux-fsdevel@vger.kernel.org
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git
@@@ -16369,6 -16326,7 +16370,6 @@@ F:   drivers/media/rc/pwm-ir-tx.
  PWM SUBSYSTEM
  M:    Thierry Reding <thierry.reding@gmail.com>
  R:    Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
 -M:    Lee Jones <lee.jones@linaro.org>
  L:    linux-pwm@vger.kernel.org
  S:    Maintained
  Q:    https://patchwork.ozlabs.org/project/linux-pwm/list/
@@@ -16379,7 -16337,6 +16380,7 @@@ F:   Documentation/driver-api/pwm.rs
  F:    drivers/gpio/gpio-mvebu.c
  F:    drivers/pwm/
  F:    drivers/video/backlight/pwm_bl.c
 +F:    include/dt-bindings/pwm/
  F:    include/linux/pwm.h
  F:    include/linux/pwm_backlight.h
  K:    pwm_(config|apply_state|ops)
@@@ -16704,13 -16661,6 +16705,13 @@@ S: Maintaine
  F:    Documentation/devicetree/bindings/i2c/i2c-qcom-cci.txt
  F:    drivers/i2c/busses/i2c-qcom-cci.c
  
 +QUALCOMM INTERCONNECT BWMON DRIVER
 +M:    Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
 +L:    linux-arm-msm@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
 +F:    drivers/soc/qcom/icc-bwmon.c
 +
  QUALCOMM IOMMU
  M:    Rob Clark <robdclark@gmail.com>
  L:    iommu@lists.linux.dev
@@@ -17334,7 -17284,6 +17335,7 @@@ F:   drivers/clk/microchip/clk-mpfs.
  F:    drivers/mailbox/mailbox-mpfs.c
  F:    drivers/pci/controller/pcie-microchip-host.c
  F:    drivers/soc/microchip/
 +F:    drivers/spi/spi-microchip-core.c
  F:    include/soc/microchip/mpfs.h
  
  RNBD BLOCK DRIVERS
  #include <linux/bits.h>
  #include <linux/of.h>
  #include <linux/io.h>
 -#include <linux/io-64-nonatomic-hi-lo.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/pm_opp.h>
  #include <linux/scmi_protocol.h>
  #include <linux/sort.h>
  
 +#include <trace/events/scmi.h>
 +
  #include "protocols.h"
  #include "notify.h"
  
@@@ -36,12 -35,6 +36,12 @@@ enum scmi_performance_protocol_cmd 
        PERF_DOMAIN_NAME_GET = 0xc,
  };
  
 +enum {
 +      PERF_FC_LEVEL,
 +      PERF_FC_LIMIT,
 +      PERF_FC_MAX,
 +};
 +
  struct scmi_opp {
        u32 perf;
        u32 power;
@@@ -122,6 -115,43 +122,6 @@@ struct scmi_msg_resp_perf_describe_leve
        } opp[];
  };
  
 -struct scmi_perf_get_fc_info {
 -      __le32 domain;
 -      __le32 message_id;
 -};
 -
 -struct scmi_msg_resp_perf_desc_fc {
 -      __le32 attr;
 -#define SUPPORTS_DOORBELL(x)          ((x) & BIT(0))
 -#define DOORBELL_REG_WIDTH(x)         FIELD_GET(GENMASK(2, 1), (x))
 -      __le32 rate_limit;
 -      __le32 chan_addr_low;
 -      __le32 chan_addr_high;
 -      __le32 chan_size;
 -      __le32 db_addr_low;
 -      __le32 db_addr_high;
 -      __le32 db_set_lmask;
 -      __le32 db_set_hmask;
 -      __le32 db_preserve_lmask;
 -      __le32 db_preserve_hmask;
 -};
 -
 -struct scmi_fc_db_info {
 -      int width;
 -      u64 set;
 -      u64 mask;
 -      void __iomem *addr;
 -};
 -
 -struct scmi_fc_info {
 -      void __iomem *level_set_addr;
 -      void __iomem *limit_set_addr;
 -      void __iomem *level_get_addr;
 -      void __iomem *limit_get_addr;
 -      struct scmi_fc_db_info *level_set_db;
 -      struct scmi_fc_db_info *limit_set_db;
 -};
 -
  struct perf_dom_info {
        bool set_limits;
        bool set_perf;
  struct scmi_perf_info {
        u32 version;
        int num_domains;
-       bool power_scale_mw;
-       bool power_scale_uw;
+       enum scmi_power_scale power_scale;
        u64 stats_addr;
        u32 stats_size;
        struct perf_dom_info *dom_info;
@@@ -171,9 -200,13 +170,13 @@@ static int scmi_perf_attributes_get(con
                u16 flags = le16_to_cpu(attr->flags);
  
                pi->num_domains = le16_to_cpu(attr->num_domains);
-               pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags);
+               if (POWER_SCALE_IN_MILLIWATT(flags))
+                       pi->power_scale = SCMI_POWER_MILLIWATTS;
                if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3)
-                       pi->power_scale_uw = POWER_SCALE_IN_MICROWATT(flags);
+                       if (POWER_SCALE_IN_MICROWATT(flags))
+                               pi->power_scale = SCMI_POWER_MICROWATTS;
                pi->stats_addr = le32_to_cpu(attr->stats_addr_low) |
                                (u64)le32_to_cpu(attr->stats_addr_high) << 32;
                pi->stats_size = le32_to_cpu(attr->stats_size);
@@@ -330,6 -363,40 +333,6 @@@ scmi_perf_describe_levels_get(const str
        return ret;
  }
  
 -#define SCMI_PERF_FC_RING_DB(w)                               \
 -do {                                                  \
 -      u##w val = 0;                                   \
 -                                                      \
 -      if (db->mask)                                   \
 -              val = ioread##w(db->addr) & db->mask;   \
 -      iowrite##w((u##w)db->set | val, db->addr);      \
 -} while (0)
 -
 -static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
 -{
 -      if (!db || !db->addr)
 -              return;
 -
 -      if (db->width == 1)
 -              SCMI_PERF_FC_RING_DB(8);
 -      else if (db->width == 2)
 -              SCMI_PERF_FC_RING_DB(16);
 -      else if (db->width == 4)
 -              SCMI_PERF_FC_RING_DB(32);
 -      else /* db->width == 8 */
 -#ifdef CONFIG_64BIT
 -              SCMI_PERF_FC_RING_DB(64);
 -#else
 -      {
 -              u64 val = 0;
 -
 -              if (db->mask)
 -                      val = ioread64_hi_lo(db->addr) & db->mask;
 -              iowrite64_hi_lo(db->set | val, db->addr);
 -      }
 -#endif
 -}
 -
  static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph,
                                   u32 domain, u32 max_perf, u32 min_perf)
  {
@@@ -362,14 -429,10 +365,14 @@@ static int scmi_perf_limits_set(const s
        if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
                return -EINVAL;
  
 -      if (dom->fc_info && dom->fc_info->limit_set_addr) {
 -              iowrite32(max_perf, dom->fc_info->limit_set_addr);
 -              iowrite32(min_perf, dom->fc_info->limit_set_addr + 4);
 -              scmi_perf_fc_ring_db(dom->fc_info->limit_set_db);
 +      if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].set_addr) {
 +              struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT];
 +
 +              trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_SET,
 +                                 domain, min_perf, max_perf);
 +              iowrite32(max_perf, fci->set_addr);
 +              iowrite32(min_perf, fci->set_addr + 4);
 +              ph->hops->fastchannel_db_ring(fci->set_db);
                return 0;
        }
  
@@@ -408,13 -471,9 +411,13 @@@ static int scmi_perf_limits_get(const s
        struct scmi_perf_info *pi = ph->get_priv(ph);
        struct perf_dom_info *dom = pi->dom_info + domain;
  
 -      if (dom->fc_info && dom->fc_info->limit_get_addr) {
 -              *max_perf = ioread32(dom->fc_info->limit_get_addr);
 -              *min_perf = ioread32(dom->fc_info->limit_get_addr + 4);
 +      if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].get_addr) {
 +              struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT];
 +
 +              *max_perf = ioread32(fci->get_addr);
 +              *min_perf = ioread32(fci->get_addr + 4);
 +              trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_GET,
 +                                 domain, *min_perf, *max_perf);
                return 0;
        }
  
@@@ -449,13 -508,9 +452,13 @@@ static int scmi_perf_level_set(const st
        struct scmi_perf_info *pi = ph->get_priv(ph);
        struct perf_dom_info *dom = pi->dom_info + domain;
  
 -      if (dom->fc_info && dom->fc_info->level_set_addr) {
 -              iowrite32(level, dom->fc_info->level_set_addr);
 -              scmi_perf_fc_ring_db(dom->fc_info->level_set_db);
 +      if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr) {
 +              struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LEVEL];
 +
 +              trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_SET,
 +                                 domain, level, 0);
 +              iowrite32(level, fci->set_addr);
 +              ph->hops->fastchannel_db_ring(fci->set_db);
                return 0;
        }
  
@@@ -490,10 -545,8 +493,10 @@@ static int scmi_perf_level_get(const st
        struct scmi_perf_info *pi = ph->get_priv(ph);
        struct perf_dom_info *dom = pi->dom_info + domain;
  
 -      if (dom->fc_info && dom->fc_info->level_get_addr) {
 -              *level = ioread32(dom->fc_info->level_get_addr);
 +      if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].get_addr) {
 +              *level = ioread32(dom->fc_info[PERF_FC_LEVEL].get_addr);
 +              trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_GET,
 +                                 domain, *level, 0);
                return 0;
        }
  
@@@ -522,33 -575,100 +525,33 @@@ static int scmi_perf_level_limits_notif
        return ret;
  }
  
 -static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
 -{
 -      if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)
 -              return true;
 -      if ((msg == PERF_LIMITS_GET || msg == PERF_LIMITS_SET) && size == 8)
 -              return true;
 -      return false;
 -}
 -
 -static void
 -scmi_perf_domain_desc_fc(const struct scmi_protocol_handle *ph, u32 domain,
 -                       u32 message_id, void __iomem **p_addr,
 -                       struct scmi_fc_db_info **p_db)
 -{
 -      int ret;
 -      u32 flags;
 -      u64 phys_addr;
 -      u8 size;
 -      void __iomem *addr;
 -      struct scmi_xfer *t;
 -      struct scmi_fc_db_info *db;
 -      struct scmi_perf_get_fc_info *info;
 -      struct scmi_msg_resp_perf_desc_fc *resp;
 -
 -      if (!p_addr)
 -              return;
 -
 -      ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_FASTCHANNEL,
 -                                    sizeof(*info), sizeof(*resp), &t);
 -      if (ret)
 -              return;
 -
 -      info = t->tx.buf;
 -      info->domain = cpu_to_le32(domain);
 -      info->message_id = cpu_to_le32(message_id);
 -
 -      ret = ph->xops->do_xfer(ph, t);
 -      if (ret)
 -              goto err_xfer;
 -
 -      resp = t->rx.buf;
 -      flags = le32_to_cpu(resp->attr);
 -      size = le32_to_cpu(resp->chan_size);
 -      if (!scmi_perf_fc_size_is_valid(message_id, size))
 -              goto err_xfer;
 -
 -      phys_addr = le32_to_cpu(resp->chan_addr_low);
 -      phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
 -      addr = devm_ioremap(ph->dev, phys_addr, size);
 -      if (!addr)
 -              goto err_xfer;
 -      *p_addr = addr;
 -
 -      if (p_db && SUPPORTS_DOORBELL(flags)) {
 -              db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL);
 -              if (!db)
 -                      goto err_xfer;
 -
 -              size = 1 << DOORBELL_REG_WIDTH(flags);
 -              phys_addr = le32_to_cpu(resp->db_addr_low);
 -              phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
 -              addr = devm_ioremap(ph->dev, phys_addr, size);
 -              if (!addr)
 -                      goto err_xfer;
 -
 -              db->addr = addr;
 -              db->width = size;
 -              db->set = le32_to_cpu(resp->db_set_lmask);
 -              db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;
 -              db->mask = le32_to_cpu(resp->db_preserve_lmask);
 -              db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;
 -              *p_db = db;
 -      }
 -err_xfer:
 -      ph->xops->xfer_put(ph, t);
 -}
 -
  static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
                                     u32 domain, struct scmi_fc_info **p_fc)
  {
        struct scmi_fc_info *fc;
  
 -      fc = devm_kzalloc(ph->dev, sizeof(*fc), GFP_KERNEL);
 +      fc = devm_kcalloc(ph->dev, PERF_FC_MAX, sizeof(*fc), GFP_KERNEL);
        if (!fc)
                return;
  
 -      scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_SET,
 -                               &fc->level_set_addr, &fc->level_set_db);
 -      scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_GET,
 -                               &fc->level_get_addr, NULL);
 -      scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_SET,
 -                               &fc->limit_set_addr, &fc->limit_set_db);
 -      scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_GET,
 -                               &fc->limit_get_addr, NULL);
 +      ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
 +                                 PERF_LEVEL_SET, 4, domain,
 +                                 &fc[PERF_FC_LEVEL].set_addr,
 +                                 &fc[PERF_FC_LEVEL].set_db);
 +
 +      ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
 +                                 PERF_LEVEL_GET, 4, domain,
 +                                 &fc[PERF_FC_LEVEL].get_addr, NULL);
 +
 +      ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
 +                                 PERF_LIMITS_SET, 8, domain,
 +                                 &fc[PERF_FC_LIMIT].set_addr,
 +                                 &fc[PERF_FC_LIMIT].set_db);
 +
 +      ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
 +                                 PERF_LIMITS_GET, 8, domain,
 +                                 &fc[PERF_FC_LIMIT].get_addr, NULL);
 +
        *p_fc = fc;
  }
  
@@@ -672,14 -792,15 +675,15 @@@ static bool scmi_fast_switch_possible(c
  
        dom = pi->dom_info + scmi_dev_domain_id(dev);
  
 -      return dom->fc_info && dom->fc_info->level_set_addr;
 +      return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr;
  }
  
- static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
+ static enum scmi_power_scale
+ scmi_power_scale_get(const struct scmi_protocol_handle *ph)
  {
        struct scmi_perf_info *pi = ph->get_priv(ph);
  
-       return pi->power_scale_mw;
+       return pi->power_scale;
  }
  
  static const struct scmi_perf_proto_ops perf_proto_ops = {
        .freq_get = scmi_dvfs_freq_get,
        .est_power_get = scmi_dvfs_est_power_get,
        .fast_switch_possible = scmi_fast_switch_possible,
-       .power_scale_mw_get = scmi_power_scale_mw_get,
+       .power_scale_get = scmi_power_scale_get,
  };
  
  static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
@@@ -56,7 -56,6 +56,7 @@@
  #include <asm/nospec-branch.h>
  #include <asm/mwait.h>
  #include <asm/msr.h>
 +#include <asm/fpu/api.h>
  
  #define INTEL_IDLE_VERSION "0.5.1"
  
@@@ -114,11 -113,6 +114,11 @@@ static unsigned int mwait_substates __i
   */
  #define CPUIDLE_FLAG_IBRS             BIT(16)
  
 +/*
 + * Initialize large xstate for the C6-state entrance.
 + */
 +#define CPUIDLE_FLAG_INIT_XSTATE      BIT(17)
 +
  /*
   * MWAIT takes an 8-bit "hint" in EAX "suggesting"
   * the C-state (top nibble) and sub-state (bottom nibble)
@@@ -197,13 -191,6 +197,13 @@@ static __cpuidle int intel_idle_ibrs(st
        return ret;
  }
  
 +static __cpuidle int intel_idle_xstate(struct cpuidle_device *dev,
 +                                     struct cpuidle_driver *drv, int index)
 +{
 +      fpu_idle_fpregs();
 +      return __intel_idle(dev, drv, index);
 +}
 +
  /**
   * intel_idle_s2idle - Ask the processor to enter the given idle state.
   * @dev: cpuidle device of the target CPU.
  static __cpuidle int intel_idle_s2idle(struct cpuidle_device *dev,
                                       struct cpuidle_driver *drv, int index)
  {
 -      unsigned long eax = flg2MWAIT(drv->states[index].flags);
        unsigned long ecx = 1; /* break on interrupt flag */
 +      struct cpuidle_state *state = &drv->states[index];
 +      unsigned long eax = flg2MWAIT(state->flags);
 +
 +      if (state->flags & CPUIDLE_FLAG_INIT_XSTATE)
 +              fpu_idle_fpregs();
  
        mwait_idle_with_hints(eax, ecx);
  
@@@ -928,16 -911,6 +928,6 @@@ static struct cpuidle_state adl_l_cstat
                .enter = NULL }
  };
  
- /*
-  * On Sapphire Rapids Xeon C1 has to be disabled if C1E is enabled, and vice
-  * versa. On SPR C1E is enabled only if "C1E promotion" bit is set in
-  * MSR_IA32_POWER_CTL. But in this case there effectively no C1, because C1
-  * requests are promoted to C1E. If the "C1E promotion" bit is cleared, then
-  * both C1 and C1E requests end up with C1, so there is effectively no C1E.
-  *
-  * By default we enable C1 and disable C1E by marking it with
-  * 'CPUIDLE_FLAG_UNUSABLE'.
-  */
  static struct cpuidle_state spr_cstates[] __initdata = {
        {
                .name = "C1",
        {
                .name = "C1E",
                .desc = "MWAIT 0x01",
-               .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE |
-                                          CPUIDLE_FLAG_UNUSABLE,
+               .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE,
                .exit_latency = 2,
                .target_residency = 4,
                .enter = &intel_idle,
        {
                .name = "C6",
                .desc = "MWAIT 0x20",
 -              .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
 +              .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED |
 +                                         CPUIDLE_FLAG_INIT_XSTATE,
                .exit_latency = 290,
                .target_residency = 800,
                .enter = &intel_idle,
@@@ -1774,17 -1745,6 +1763,6 @@@ static void __init spr_idle_state_table
  {
        unsigned long long msr;
  
-       /* Check if user prefers C1E over C1. */
-       if ((preferred_states_mask & BIT(2)) &&
-           !(preferred_states_mask & BIT(1))) {
-               /* Disable C1 and enable C1E. */
-               spr_cstates[0].flags |= CPUIDLE_FLAG_UNUSABLE;
-               spr_cstates[1].flags &= ~CPUIDLE_FLAG_UNUSABLE;
-               /* Enable C1E using the "C1E promotion" bit. */
-               c1e_promotion = C1E_PROMOTION_ENABLE;
-       }
        /*
         * By default, the C6 state assumes the worst-case scenario of package
         * C6. However, if PC6 is disabled, we update the numbers to match
@@@ -1875,9 -1835,6 +1853,9 @@@ static void __init intel_idle_init_csta
                        drv->states[drv->state_count].enter = intel_idle_ibrs;
                }
  
 +              if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_INIT_XSTATE)
 +                      drv->states[drv->state_count].enter = intel_idle_xstate;
 +
                if ((disabled_states_mask & BIT(drv->state_count)) ||
                    ((icpu->use_acpi || force_use_acpi) &&
                     intel_idle_off_by_default(mwait_hint) &&
@@@ -53,7 -53,7 +53,7 @@@ static u64 set_pd_power_limit(struct dt
  
        for (i = 0; i < pd->nr_perf_states; i++) {
  
-               power = pd->table[i].power * MICROWATT_PER_MILLIWATT * nr_cpus;
+               power = pd->table[i].power * nr_cpus;
  
                if (power > power_limit)
                        break;
  
        freq_qos_update_request(&dtpm_cpu->qos_req, freq);
  
-       power_limit = pd->table[i - 1].power *
-               MICROWATT_PER_MILLIWATT * nr_cpus;
+       power_limit = pd->table[i - 1].power * nr_cpus;
  
        return power_limit;
  }
  
  static u64 scale_pd_power_uw(struct cpumask *pd_mask, u64 power)
  {
 -      unsigned long max = 0, sum_util = 0;
 +      unsigned long max, sum_util = 0;
        int cpu;
  
 -      for_each_cpu_and(cpu, pd_mask, cpu_online_mask) {
 -
 -              /*
 -               * The capacity is the same for all CPUs belonging to
 -               * the same perf domain, so a single call to
 -               * arch_scale_cpu_capacity() is enough. However, we
 -               * need the CPU parameter to be initialized by the
 -               * loop, so the call ends up in this block.
 -               *
 -               * We can initialize 'max' with a cpumask_first() call
 -               * before the loop but the bits computation is not
 -               * worth given the arch_scale_cpu_capacity() just
 -               * returns a value where the resulting assembly code
 -               * will be optimized by the compiler.
 -               */
 -              max = arch_scale_cpu_capacity(cpu);
 -              sum_util += sched_cpu_util(cpu, max);
 -      }
 -
        /*
 -       * In the improbable case where all the CPUs of the perf
 -       * domain are offline, 'max' will be zero and will lead to an
 -       * illegal operation with a zero division.
 +       * The capacity is the same for all CPUs belonging to
 +       * the same perf domain.
         */
 -      return max ? (power * ((sum_util << 10) / max)) >> 10 : 0;
 +      max = arch_scale_cpu_capacity(cpumask_first(pd_mask));
 +
 +      for_each_cpu_and(cpu, pd_mask, cpu_online_mask)
 +              sum_util += sched_cpu_util(cpu);
 +
 +      return (power * ((sum_util << 10) / max)) >> 10;
  }
  
  static u64 get_pd_power_uw(struct dtpm *dtpm)
@@@ -21,6 -21,7 +21,7 @@@
  #include <linux/pm_qos.h>
  #include <linux/slab.h>
  #include <linux/thermal.h>
+ #include <linux/units.h>
  
  #include <trace/events/thermal.h>
  
@@@ -101,6 -102,7 +102,7 @@@ static unsigned long get_level(struct c
  static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 freq)
  {
+       unsigned long power_mw;
        int i;
  
        for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
                        break;
        }
  
-       return cpufreq_cdev->em->table[i + 1].power;
+       power_mw = cpufreq_cdev->em->table[i + 1].power;
+       power_mw /= MICROWATT_PER_MILLIWATT;
+       return power_mw;
  }
  
  static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 power)
  {
+       unsigned long em_power_mw;
        int i;
  
        for (i = cpufreq_cdev->max_level; i > 0; i--) {
-               if (power >= cpufreq_cdev->em->table[i].power)
+               /* Convert EM power to milli-Watts to make safe comparison */
+               em_power_mw = cpufreq_cdev->em->table[i].power;
+               em_power_mw /= MICROWATT_PER_MILLIWATT;
+               if (power >= em_power_mw)
                        break;
        }
  
  static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
                    int cpu_idx)
  {
 -      unsigned long max = arch_scale_cpu_capacity(cpu);
 -      unsigned long util;
 +      unsigned long util = sched_cpu_util(cpu);
  
 -      util = sched_cpu_util(cpu, max);
 -      return (util * 100) / max;
 +      return (util * 100) / arch_scale_cpu_capacity(cpu);
  }
  #else /* !CONFIG_SMP */
  static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
@@@ -60,6 -60,12 +60,12 @@@ struct scmi_clock_info 
        };
  };
  
+ enum scmi_power_scale {
+       SCMI_POWER_BOGOWATTS,
+       SCMI_POWER_MILLIWATTS,
+       SCMI_POWER_MICROWATTS
+ };
  struct scmi_handle;
  struct scmi_device;
  struct scmi_protocol_handle;
@@@ -135,7 -141,7 +141,7 @@@ struct scmi_perf_proto_ops 
                             unsigned long *rate, unsigned long *power);
        bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph,
                                     struct device *dev);
-       bool (*power_scale_mw_get)(const struct scmi_protocol_handle *ph);
+       enum scmi_power_scale (*power_scale_get)(const struct scmi_protocol_handle *ph);
  };
  
  /**
@@@ -560,116 -566,6 +566,116 @@@ struct scmi_voltage_proto_ops 
                         s32 *volt_uV);
  };
  
 +/**
 + * struct scmi_powercap_info  - Describe one available Powercap domain
 + *
 + * @id: Domain ID as advertised by the platform.
 + * @notify_powercap_cap_change: CAP change notification support.
 + * @notify_powercap_measurement_change: MEASUREMENTS change notifications
 + *                                   support.
 + * @async_powercap_cap_set: Asynchronous CAP set support.
 + * @powercap_cap_config: CAP configuration support.
 + * @powercap_monitoring: Monitoring (measurements) support.
 + * @powercap_pai_config: PAI configuration support.
 + * @powercap_scale_mw: Domain reports power data in milliwatt units.
 + * @powercap_scale_uw: Domain reports power data in microwatt units.
 + *                   Note that, when both @powercap_scale_mw and
 + *                   @powercap_scale_uw are set to false, the domain
 + *                   reports power data on an abstract linear scale.
 + * @name: name assigned to the Powercap Domain by platform.
 + * @min_pai: Minimum configurable PAI.
 + * @max_pai: Maximum configurable PAI.
 + * @pai_step: Step size between two consecutive PAI values.
 + * @min_power_cap: Minimum configurable CAP.
 + * @max_power_cap: Maximum configurable CAP.
 + * @power_cap_step: Step size between two consecutive CAP values.
 + * @sustainable_power: Maximum sustainable power consumption for this domain
 + *                   under normal conditions.
 + * @accuracy: The accuracy with which the power is measured and reported in
 + *          integral multiples of 0.001 percent.
 + * @parent_id: Identifier of the containing parent power capping domain, or the
 + *           value 0xFFFFFFFF if this powercap domain is a root domain not
 + *           contained in any other domain.
 + */
 +struct scmi_powercap_info {
 +      unsigned int id;
 +      bool notify_powercap_cap_change;
 +      bool notify_powercap_measurement_change;
 +      bool async_powercap_cap_set;
 +      bool powercap_cap_config;
 +      bool powercap_monitoring;
 +      bool powercap_pai_config;
 +      bool powercap_scale_mw;
 +      bool powercap_scale_uw;
 +      bool fastchannels;
 +      char name[SCMI_MAX_STR_SIZE];
 +      unsigned int min_pai;
 +      unsigned int max_pai;
 +      unsigned int pai_step;
 +      unsigned int min_power_cap;
 +      unsigned int max_power_cap;
 +      unsigned int power_cap_step;
 +      unsigned int sustainable_power;
 +      unsigned int accuracy;
 +#define SCMI_POWERCAP_ROOT_ZONE_ID     0xFFFFFFFFUL
 +      unsigned int parent_id;
 +      struct scmi_fc_info *fc_info;
 +};
 +
 +/**
 + * struct scmi_powercap_proto_ops - represents the various operations provided
 + * by SCMI Powercap Protocol
 + *
 + * @num_domains_get: get the count of powercap domains provided by SCMI.
 + * @info_get: get the information for the specified domain.
 + * @cap_get: get the current CAP value for the specified domain.
 + * @cap_set: set the CAP value for the specified domain to the provided value;
 + *         if the domain supports setting the CAP with an asynchronous command
 + *         this request will finally trigger an asynchronous transfer, but, if
 + *         @ignore_dresp here is set to true, this call will anyway return
 + *         immediately without waiting for the related delayed response.
 + * @pai_get: get the current PAI value for the specified domain.
 + * @pai_set: set the PAI value for the specified domain to the provided value.
 + * @measurements_get: retrieve the current average power measurements for the
 + *                  specified domain and the related PAI upon which is
 + *                  calculated.
 + * @measurements_threshold_set: set the desired low and high power thresholds
 + *                            to be used when registering for notification
 + *                            of type POWERCAP_MEASUREMENTS_NOTIFY with this
 + *                            powercap domain.
 + *                            Note that this must be called at least once
 + *                            before registering any callback with the usual
 + *                            @scmi_notify_ops; moreover, in case this method
 + *                            is called with measurement notifications already
 + *                            enabled it will also trigger, transparently, a
 + *                            proper update of the power thresholds configured
 + *                            in the SCMI backend server.
 + * @measurements_threshold_get: get the currently configured low and high power
 + *                            thresholds used when registering callbacks for
 + *                            notification POWERCAP_MEASUREMENTS_NOTIFY.
 + */
 +struct scmi_powercap_proto_ops {
 +      int (*num_domains_get)(const struct scmi_protocol_handle *ph);
 +      const struct scmi_powercap_info __must_check *(*info_get)
 +              (const struct scmi_protocol_handle *ph, u32 domain_id);
 +      int (*cap_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
 +                     u32 *power_cap);
 +      int (*cap_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
 +                     u32 power_cap, bool ignore_dresp);
 +      int (*pai_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
 +                     u32 *pai);
 +      int (*pai_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
 +                     u32 pai);
 +      int (*measurements_get)(const struct scmi_protocol_handle *ph,
 +                              u32 domain_id, u32 *average_power, u32 *pai);
 +      int (*measurements_threshold_set)(const struct scmi_protocol_handle *ph,
 +                                        u32 domain_id, u32 power_thresh_low,
 +                                        u32 power_thresh_high);
 +      int (*measurements_threshold_get)(const struct scmi_protocol_handle *ph,
 +                                        u32 domain_id, u32 *power_thresh_low,
 +                                        u32 *power_thresh_high);
 +};
 +
  /**
   * struct scmi_notify_ops  - represents notifications' operations provided by
   * SCMI core
@@@ -734,9 -630,6 +740,9 @@@ struct scmi_notify_ops 
   *
   * @dev: pointer to the SCMI device
   * @version: pointer to the structure containing SCMI version information
 + * @devm_protocol_acquire: devres managed method to get hold of a protocol,
 + *                       causing its initialization and related resource
 + *                       accounting
   * @devm_protocol_get: devres managed method to acquire a protocol and get specific
   *                   operations and a dedicated protocol handler
   * @devm_protocol_put: devres managed method to release a protocol
@@@ -755,8 -648,6 +761,8 @@@ struct scmi_handle 
        struct device *dev;
        struct scmi_revision_info *version;
  
 +      int __must_check (*devm_protocol_acquire)(struct scmi_device *sdev,
 +                                                u8 proto);
        const void __must_check *
                (*devm_protocol_get)(struct scmi_device *sdev, u8 proto,
                                     struct scmi_protocol_handle **ph);
@@@ -776,7 -667,6 +782,7 @@@ enum scmi_std_protocol 
        SCMI_PROTOCOL_SENSOR = 0x15,
        SCMI_PROTOCOL_RESET = 0x16,
        SCMI_PROTOCOL_VOLTAGE = 0x17,
 +      SCMI_PROTOCOL_POWERCAP = 0x18,
  };
  
  enum scmi_system_events {
@@@ -878,8 -768,6 +884,8 @@@ enum scmi_notification_events 
        SCMI_EVENT_RESET_ISSUED = 0x0,
        SCMI_EVENT_BASE_ERROR_EVENT = 0x0,
        SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER = 0x0,
 +      SCMI_EVENT_POWERCAP_CAP_CHANGED = 0x0,
 +      SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED = 0x1,
  };
  
  struct scmi_power_state_changed_report {
@@@ -899,10 -787,8 +905,10 @@@ struct scmi_clock_rate_notif_report 
  struct scmi_system_power_state_notifier_report {
        ktime_t         timestamp;
        unsigned int    agent_id;
 +#define SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(flags)      ((flags) & BIT(0))
        unsigned int    flags;
        unsigned int    system_state;
 +      unsigned int    timeout;
  };
  
  struct scmi_perf_limits_report {
@@@ -950,18 -836,4 +956,18 @@@ struct scmi_base_error_report 
        unsigned long long      reports[];
  };
  
 +struct scmi_powercap_cap_changed_report {
 +      ktime_t         timestamp;
 +      unsigned int    agent_id;
 +      unsigned int    domain_id;
 +      unsigned int    power_cap;
 +      unsigned int    pai;
 +};
 +
 +struct scmi_powercap_meas_changed_report {
 +      ktime_t         timestamp;
 +      unsigned int    agent_id;
 +      unsigned int    domain_id;
 +      unsigned int    power;
 +};
  #endif /* _LINUX_SCMI_PROTOCOL_H */