@@ -108,6 +108,8 @@ struct scmi_powercap_meas_changed_notify_payld {
108108};
109109
110110struct scmi_powercap_state {
111+ bool enabled ;
112+ u32 last_pcap ;
111113 bool meas_notif_enabled ;
112114 u64 thresholds ;
113115#define THRESH_LOW (p , id ) \
@@ -412,6 +414,10 @@ static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
412414 ignore_dresp );
413415 }
414416
417+ /* Save the last explicitly set non-zero powercap value */
418+ if (PROTOCOL_REV_MAJOR (pi -> version ) >= 0x2 && !ret && power_cap )
419+ pi -> states [domain_id ].last_pcap = power_cap ;
420+
415421 return ret ;
416422}
417423
@@ -421,6 +427,20 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
421427{
422428 struct powercap_info * pi = ph -> get_priv (ph );
423429
430+ /*
431+ * Disallow zero as a possible explicitly requested powercap:
432+ * there are enable/disable operations for this.
433+ */
434+ if (!power_cap )
435+ return - EINVAL ;
436+
437+ /* Just log the last set request if acting on a disabled domain */
438+ if (PROTOCOL_REV_MAJOR (pi -> version ) >= 0x2 &&
439+ !pi -> states [domain_id ].enabled ) {
440+ pi -> states [domain_id ].last_pcap = power_cap ;
441+ return 0 ;
442+ }
443+
424444 return __scmi_powercap_cap_set (ph , pi , domain_id ,
425445 power_cap , ignore_dresp );
426446}
@@ -589,11 +609,78 @@ scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
589609 return ret ;
590610}
591611
612+ static int scmi_powercap_cap_enable_set (const struct scmi_protocol_handle * ph ,
613+ u32 domain_id , bool enable )
614+ {
615+ int ret ;
616+ u32 power_cap ;
617+ struct powercap_info * pi = ph -> get_priv (ph );
618+
619+ if (PROTOCOL_REV_MAJOR (pi -> version ) < 0x2 )
620+ return - EINVAL ;
621+
622+ if (enable == pi -> states [domain_id ].enabled )
623+ return 0 ;
624+
625+ if (enable ) {
626+ /* Cannot enable with a zero powercap. */
627+ if (!pi -> states [domain_id ].last_pcap )
628+ return - EINVAL ;
629+
630+ ret = __scmi_powercap_cap_set (ph , pi , domain_id ,
631+ pi -> states [domain_id ].last_pcap ,
632+ true);
633+ } else {
634+ ret = __scmi_powercap_cap_set (ph , pi , domain_id , 0 , true);
635+ }
636+
637+ if (ret )
638+ return ret ;
639+
640+ /*
641+ * Update our internal state to reflect final platform state: the SCMI
642+ * server could have ignored a disable request and kept enforcing some
643+ * powercap limit requested by other agents.
644+ */
645+ ret = scmi_powercap_cap_get (ph , domain_id , & power_cap );
646+ if (!ret )
647+ pi -> states [domain_id ].enabled = !!power_cap ;
648+
649+ return ret ;
650+ }
651+
652+ static int scmi_powercap_cap_enable_get (const struct scmi_protocol_handle * ph ,
653+ u32 domain_id , bool * enable )
654+ {
655+ int ret ;
656+ u32 power_cap ;
657+ struct powercap_info * pi = ph -> get_priv (ph );
658+
659+ * enable = true;
660+ if (PROTOCOL_REV_MAJOR (pi -> version ) < 0x2 )
661+ return 0 ;
662+
663+ /*
664+ * Report always real platform state; platform could have ignored
665+ * a previous disable request. Default true on any error.
666+ */
667+ ret = scmi_powercap_cap_get (ph , domain_id , & power_cap );
668+ if (!ret )
669+ * enable = !!power_cap ;
670+
671+ /* Update internal state with current real platform state */
672+ pi -> states [domain_id ].enabled = * enable ;
673+
674+ return 0 ;
675+ }
676+
592677static const struct scmi_powercap_proto_ops powercap_proto_ops = {
593678 .num_domains_get = scmi_powercap_num_domains_get ,
594679 .info_get = scmi_powercap_dom_info_get ,
595680 .cap_get = scmi_powercap_cap_get ,
596681 .cap_set = scmi_powercap_cap_set ,
682+ .cap_enable_set = scmi_powercap_cap_enable_set ,
683+ .cap_enable_get = scmi_powercap_cap_enable_get ,
597684 .pai_get = scmi_powercap_pai_get ,
598685 .pai_set = scmi_powercap_pai_set ,
599686 .measurements_get = scmi_powercap_measurements_get ,
@@ -854,6 +941,11 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
854941 if (!pinfo -> powercaps )
855942 return - ENOMEM ;
856943
944+ pinfo -> states = devm_kcalloc (ph -> dev , pinfo -> num_domains ,
945+ sizeof (* pinfo -> states ), GFP_KERNEL );
946+ if (!pinfo -> states )
947+ return - ENOMEM ;
948+
857949 /*
858950 * Note that any failure in retrieving any domain attribute leads to
859951 * the whole Powercap protocol initialization failure: this way the
@@ -868,15 +960,21 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
868960 if (pinfo -> powercaps [domain ].fastchannels )
869961 scmi_powercap_domain_init_fc (ph , domain ,
870962 & pinfo -> powercaps [domain ].fc_info );
871- }
872963
873- pinfo -> states = devm_kcalloc (ph -> dev , pinfo -> num_domains ,
874- sizeof (* pinfo -> states ), GFP_KERNEL );
875- if (!pinfo -> states )
876- return - ENOMEM ;
964+ /* Grab initial state when disable is supported. */
965+ if (PROTOCOL_REV_MAJOR (version ) >= 0x2 ) {
966+ ret = __scmi_powercap_cap_get (ph ,
967+ & pinfo -> powercaps [domain ],
968+ & pinfo -> states [domain ].last_pcap );
969+ if (ret )
970+ return ret ;
877971
878- pinfo -> version = version ;
972+ pinfo -> states [domain ].enabled =
973+ !!pinfo -> states [domain ].last_pcap ;
974+ }
975+ }
879976
977+ pinfo -> version = version ;
880978 return ph -> set_priv (ph , pinfo );
881979}
882980
0 commit comments