File Index
Files and directories
Sign in
FILE

powercap.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/arm_scmi/powercap.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * System Control and Management Interface (SCMI) Powercap Protocol
   4 *
   5 * Copyright (C) 2022 ARM Ltd.
   6 */
   7
   8#define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
   9
  10#include <linux/bitfield.h>
  11#include <linux/io.h>
  12#include <linux/module.h>
  13#include <linux/scmi_protocol.h>
  14
  15#include <trace/events/scmi.h>
  16
  17#include "protocols.h"
  18#include "notify.h"
  19
  20/* Updated only after ALL the mandatory features for that version are merged */
  21#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x20000
  22
  23enum scmi_powercap_protocol_cmd {
  24	POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
  25	POWERCAP_CAP_GET = 0x4,
  26	POWERCAP_CAP_SET = 0x5,
  27	POWERCAP_PAI_GET = 0x6,
  28	POWERCAP_PAI_SET = 0x7,
  29	POWERCAP_DOMAIN_NAME_GET = 0x8,
  30	POWERCAP_MEASUREMENTS_GET = 0x9,
  31	POWERCAP_CAP_NOTIFY = 0xa,
  32	POWERCAP_MEASUREMENTS_NOTIFY = 0xb,
  33	POWERCAP_DESCRIBE_FASTCHANNEL = 0xc,
  34};
  35
  36enum {
  37	POWERCAP_FC_CAP,
  38	POWERCAP_FC_PAI,
  39	POWERCAP_FC_MAX,
  40};
  41
  42struct scmi_msg_resp_powercap_domain_attributes {
  43	__le32 attributes;
  44#define SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(x)		((x) & BIT(31))
  45#define SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(x)	((x) & BIT(30))
  46#define SUPPORTS_ASYNC_POWERCAP_CAP_SET(x)		((x) & BIT(29))
  47#define SUPPORTS_EXTENDED_NAMES(x)			((x) & BIT(28))
  48#define SUPPORTS_POWERCAP_CAP_CONFIGURATION(x)		((x) & BIT(27))
  49#define SUPPORTS_POWERCAP_MONITORING(x)			((x) & BIT(26))
  50#define SUPPORTS_POWERCAP_PAI_CONFIGURATION(x)		((x) & BIT(25))
  51#define SUPPORTS_POWERCAP_FASTCHANNELS(x)		((x) & BIT(22))
  52#define POWERCAP_POWER_UNIT(x)				\
  53		(FIELD_GET(GENMASK(24, 23), (x)))
  54#define	SUPPORTS_POWER_UNITS_MW(x)			\
  55		(POWERCAP_POWER_UNIT(x) == 0x2)
  56#define	SUPPORTS_POWER_UNITS_UW(x)			\
  57		(POWERCAP_POWER_UNIT(x) == 0x1)
  58	u8 name[SCMI_SHORT_NAME_MAX_SIZE];
  59	__le32 min_pai;
  60	__le32 max_pai;
  61	__le32 pai_step;
  62	__le32 min_power_cap;
  63	__le32 max_power_cap;
  64	__le32 power_cap_step;
  65	__le32 sustainable_power;
  66	__le32 accuracy;
  67	__le32 parent_id;
  68};
  69
  70struct scmi_msg_powercap_set_cap_or_pai {
  71	__le32 domain;
  72	__le32 flags;
  73#define CAP_SET_ASYNC		BIT(1)
  74#define CAP_SET_IGNORE_DRESP	BIT(0)
  75	__le32 value;
  76};
  77
  78struct scmi_msg_resp_powercap_cap_set_complete {
  79	__le32 domain;
  80	__le32 power_cap;
  81};
  82
  83struct scmi_msg_resp_powercap_meas_get {
  84	__le32 power;
  85	__le32 pai;
  86};
  87
  88struct scmi_msg_powercap_notify_cap {
  89	__le32 domain;
  90	__le32 notify_enable;
  91};
  92
  93struct scmi_msg_powercap_notify_thresh {
  94	__le32 domain;
  95	__le32 notify_enable;
  96	__le32 power_thresh_low;
  97	__le32 power_thresh_high;
  98};
  99
 100struct scmi_powercap_cap_changed_notify_payld {
 101	__le32 agent_id;
 102	__le32 domain_id;
 103	__le32 power_cap;
 104	__le32 pai;
 105};
 106
 107struct scmi_powercap_meas_changed_notify_payld {
 108	__le32 agent_id;
 109	__le32 domain_id;
 110	__le32 power;
 111};
 112
 113struct scmi_powercap_state {
 114	bool enabled;
 115	u32 last_pcap;
 116	bool meas_notif_enabled;
 117	u64 thresholds;
 118#define THRESH_LOW(p, id)				\
 119	(lower_32_bits((p)->states[(id)].thresholds))
 120#define THRESH_HIGH(p, id)				\
 121	(upper_32_bits((p)->states[(id)].thresholds))
 122};
 123
 124struct powercap_info {
 125	u32 version;
 126	int num_domains;
 127	bool notify_cap_cmd;
 128	bool notify_measurements_cmd;
 129	struct scmi_powercap_state *states;
 130	struct scmi_powercap_info *powercaps;
 131};
 132
 133static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
 134	POWERCAP_CAP_NOTIFY,
 135	POWERCAP_MEASUREMENTS_NOTIFY,
 136};
 137
 138static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
 139				u32 domain, int message_id, bool enable);
 140
 141static int
 142scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
 143			     struct powercap_info *pi)
 144{
 145	int ret;
 146	struct scmi_xfer *t;
 147
 148	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
 149				      sizeof(u32), &t);
 150	if (ret)
 151		return ret;
 152
 153	ret = ph->xops->do_xfer(ph, t);
 154	if (!ret) {
 155		u32 attributes;
 156
 157		attributes = get_unaligned_le32(t->rx.buf);
 158		pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
 159	}
 160
 161	ph->xops->xfer_put(ph, t);
 162
 163	if (!ret) {
 164		if (!ph->hops->protocol_msg_check(ph,
 165						  POWERCAP_CAP_NOTIFY, NULL))
 166			pi->notify_cap_cmd = true;
 167
 168		if (!ph->hops->protocol_msg_check(ph,
 169						  POWERCAP_MEASUREMENTS_NOTIFY,
 170						  NULL))
 171			pi->notify_measurements_cmd = true;
 172	}
 173
 174	return ret;
 175}
 176
 177static inline int
 178scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
 179		       unsigned int step_val, bool configurable)
 180{
 181	if (!min_val || !max_val)
 182		return -EPROTO;
 183
 184	if ((configurable && min_val == max_val) ||
 185	    (!configurable && min_val != max_val))
 186		return -EPROTO;
 187
 188	if (min_val != max_val && !step_val)
 189		return -EPROTO;
 190
 191	return 0;
 192}
 193
 194static int
 195scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
 196				    struct powercap_info *pinfo, u32 domain)
 197{
 198	int ret;
 199	u32 flags;
 200	struct scmi_xfer *t;
 201	struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
 202	struct scmi_msg_resp_powercap_domain_attributes *resp;
 203
 204	ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
 205				      sizeof(domain), sizeof(*resp), &t);
 206	if (ret)
 207		return ret;
 208
 209	put_unaligned_le32(domain, t->tx.buf);
 210	resp = t->rx.buf;
 211
 212	ret = ph->xops->do_xfer(ph, t);
 213	if (!ret) {
 214		flags = le32_to_cpu(resp->attributes);
 215
 216		dom_info->id = domain;
 217		if (pinfo->notify_cap_cmd)
 218			dom_info->notify_powercap_cap_change =
 219				SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
 220		if (pinfo->notify_measurements_cmd)
 221			dom_info->notify_powercap_measurement_change =
 222				SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
 223		dom_info->async_powercap_cap_set =
 224			SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
 225		dom_info->powercap_cap_config =
 226			SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
 227		dom_info->powercap_monitoring =
 228			SUPPORTS_POWERCAP_MONITORING(flags);
 229		dom_info->powercap_pai_config =
 230			SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
 231		dom_info->powercap_scale_mw =
 232			SUPPORTS_POWER_UNITS_MW(flags);
 233		dom_info->powercap_scale_uw =
 234			SUPPORTS_POWER_UNITS_UW(flags);
 235		dom_info->fastchannels =
 236			SUPPORTS_POWERCAP_FASTCHANNELS(flags);
 237
 238		strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
 239
 240		dom_info->min_pai = le32_to_cpu(resp->min_pai);
 241		dom_info->max_pai = le32_to_cpu(resp->max_pai);
 242		dom_info->pai_step = le32_to_cpu(resp->pai_step);
 243		ret = scmi_powercap_validate(dom_info->min_pai,
 244					     dom_info->max_pai,
 245					     dom_info->pai_step,
 246					     dom_info->powercap_pai_config);
 247		if (ret) {
 248			dev_err(ph->dev,
 249				"Platform reported inconsistent PAI config for domain %d - %s\n",
 250				dom_info->id, dom_info->name);
 251			goto clean;
 252		}
 253
 254		dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
 255		dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
 256		dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
 257		ret = scmi_powercap_validate(dom_info->min_power_cap,
 258					     dom_info->max_power_cap,
 259					     dom_info->power_cap_step,
 260					     dom_info->powercap_cap_config);
 261		if (ret) {
 262			dev_err(ph->dev,
 263				"Platform reported inconsistent CAP config for domain %d - %s\n",
 264				dom_info->id, dom_info->name);
 265			goto clean;
 266		}
 267
 268		dom_info->sustainable_power =
 269			le32_to_cpu(resp->sustainable_power);
 270		dom_info->accuracy = le32_to_cpu(resp->accuracy);
 271
 272		dom_info->parent_id = le32_to_cpu(resp->parent_id);
 273		if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
 274		    (dom_info->parent_id >= pinfo->num_domains ||
 275		     dom_info->parent_id == dom_info->id)) {
 276			dev_err(ph->dev,
 277				"Platform reported inconsistent parent ID for domain %d - %s\n",
 278				dom_info->id, dom_info->name);
 279			ret = -ENODEV;
 280		}
 281	}
 282
 283clean:
 284	ph->xops->xfer_put(ph, t);
 285
 286	/*
 287	 * If supported overwrite short name with the extended one;
 288	 * on error just carry on and use already provided short name.
 289	 */
 290	if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
 291		ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
 292					    domain, NULL, dom_info->name,
 293					    SCMI_MAX_STR_SIZE);
 294
 295	return ret;
 296}
 297
 298static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
 299{
 300	struct powercap_info *pi = ph->get_priv(ph);
 301
 302	return pi->num_domains;
 303}
 304
 305static const struct scmi_powercap_info *
 306scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
 307{
 308	struct powercap_info *pi = ph->get_priv(ph);
 309
 310	if (domain_id >= pi->num_domains)
 311		return NULL;
 312
 313	return pi->powercaps + domain_id;
 314}
 315
 316static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
 317				      u32 domain_id, u32 *power_cap)
 318{
 319	int ret;
 320	struct scmi_xfer *t;
 321
 322	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
 323				      sizeof(u32), &t);
 324	if (ret)
 325		return ret;
 326
 327	put_unaligned_le32(domain_id, t->tx.buf);
 328	ret = ph->xops->do_xfer(ph, t);
 329	if (!ret)
 330		*power_cap = get_unaligned_le32(t->rx.buf);
 331
 332	ph->xops->xfer_put(ph, t);
 333
 334	return ret;
 335}
 336
 337static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
 338				   const struct scmi_powercap_info *dom,
 339				   u32 *power_cap)
 340{
 341	if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
 342		*power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
 343		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
 344				   dom->id, *power_cap, 0);
 345		return 0;
 346	}
 347
 348	return scmi_powercap_xfer_cap_get(ph, dom->id, power_cap);
 349}
 350
 351static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
 352				 u32 domain_id, u32 *power_cap)
 353{
 354	const struct scmi_powercap_info *dom;
 355
 356	if (!power_cap)
 357		return -EINVAL;
 358
 359	dom = scmi_powercap_dom_info_get(ph, domain_id);
 360	if (!dom)
 361		return -EINVAL;
 362
 363	return __scmi_powercap_cap_get(ph, dom, power_cap);
 364}
 365
 366static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
 367				      const struct scmi_powercap_info *pc,
 368				      u32 power_cap, bool ignore_dresp)
 369{
 370	int ret;
 371	struct scmi_xfer *t;
 372	struct scmi_msg_powercap_set_cap_or_pai *msg;
 373
 374	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
 375				      sizeof(*msg), 0, &t);
 376	if (ret)
 377		return ret;
 378
 379	msg = t->tx.buf;
 380	msg->domain = cpu_to_le32(pc->id);
 381	msg->flags =
 382		cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, pc->async_powercap_cap_set) |
 383			    FIELD_PREP(CAP_SET_IGNORE_DRESP, ignore_dresp));
 384	msg->value = cpu_to_le32(power_cap);
 385
 386	if (!pc->async_powercap_cap_set || ignore_dresp) {
 387		ret = ph->xops->do_xfer(ph, t);
 388	} else {
 389		ret = ph->xops->do_xfer_with_response(ph, t);
 390		if (!ret) {
 391			struct scmi_msg_resp_powercap_cap_set_complete *resp;
 392
 393			resp = t->rx.buf;
 394			if (le32_to_cpu(resp->domain) == pc->id)
 395				dev_dbg(ph->dev,
 396					"Powercap ID %d CAP set async to %u\n",
 397					pc->id,
 398					get_unaligned_le32(&resp->power_cap));
 399			else
 400				ret = -EPROTO;
 401		}
 402	}
 403
 404	ph->xops->xfer_put(ph, t);
 405	return ret;
 406}
 407
 408static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 409				   struct powercap_info *pi, u32 domain_id,
 410				   u32 power_cap, bool ignore_dresp)
 411{
 412	int ret = -EINVAL;
 413	const struct scmi_powercap_info *pc;
 414
 415	pc = scmi_powercap_dom_info_get(ph, domain_id);
 416	if (!pc || !pc->powercap_cap_config)
 417		return ret;
 418
 419	if (power_cap &&
 420	    (power_cap < pc->min_power_cap || power_cap > pc->max_power_cap))
 421		return ret;
 422
 423	if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
 424		struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
 425
 426		iowrite32(power_cap, fci->set_addr);
 427		ph->hops->fastchannel_db_ring(fci->set_db);
 428		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
 429				   domain_id, power_cap, 0);
 430		ret = 0;
 431	} else {
 432		ret = scmi_powercap_xfer_cap_set(ph, pc, power_cap,
 433						 ignore_dresp);
 434	}
 435
 436	/* Save the last explicitly set non-zero powercap value */
 437	if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 && !ret && power_cap)
 438		pi->states[domain_id].last_pcap = power_cap;
 439
 440	return ret;
 441}
 442
 443static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 444				 u32 domain_id, u32 power_cap,
 445				 bool ignore_dresp)
 446{
 447	struct powercap_info *pi = ph->get_priv(ph);
 448
 449	/*
 450	 * Disallow zero as a possible explicitly requested powercap:
 451	 * there are enable/disable operations for this.
 452	 */
 453	if (!power_cap)
 454		return -EINVAL;
 455
 456	/* Just log the last set request if acting on a disabled domain */
 457	if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 &&
 458	    !pi->states[domain_id].enabled) {
 459		pi->states[domain_id].last_pcap = power_cap;
 460		return 0;
 461	}
 462
 463	return __scmi_powercap_cap_set(ph, pi, domain_id,
 464				       power_cap, ignore_dresp);
 465}
 466
 467static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
 468				      u32 domain_id, u32 *pai)
 469{
 470	int ret;
 471	struct scmi_xfer *t;
 472
 473	ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
 474				      sizeof(u32), &t);
 475	if (ret)
 476		return ret;
 477
 478	put_unaligned_le32(domain_id, t->tx.buf);
 479	ret = ph->xops->do_xfer(ph, t);
 480	if (!ret)
 481		*pai = get_unaligned_le32(t->rx.buf);
 482
 483	ph->xops->xfer_put(ph, t);
 484
 485	return ret;
 486}
 487
 488static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
 489				 u32 domain_id, u32 *pai)
 490{
 491	struct scmi_powercap_info *dom;
 492	struct powercap_info *pi = ph->get_priv(ph);
 493
 494	if (!pai || domain_id >= pi->num_domains)
 495		return -EINVAL;
 496
 497	dom = pi->powercaps + domain_id;
 498	if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
 499		*pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
 500		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
 501				   domain_id, *pai, 0);
 502		return 0;
 503	}
 504
 505	return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
 506}
 507
 508static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
 509				      u32 domain_id, u32 pai)
 510{
 511	int ret;
 512	struct scmi_xfer *t;
 513	struct scmi_msg_powercap_set_cap_or_pai *msg;
 514
 515	ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
 516				      sizeof(*msg), 0, &t);
 517	if (ret)
 518		return ret;
 519
 520	msg = t->tx.buf;
 521	msg->domain = cpu_to_le32(domain_id);
 522	msg->flags = cpu_to_le32(0);
 523	msg->value = cpu_to_le32(pai);
 524
 525	ret = ph->xops->do_xfer(ph, t);
 526
 527	ph->xops->xfer_put(ph, t);
 528	return ret;
 529}
 530
 531static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
 532				 u32 domain_id, u32 pai)
 533{
 534	const struct scmi_powercap_info *pc;
 535
 536	pc = scmi_powercap_dom_info_get(ph, domain_id);
 537	if (!pc || !pc->powercap_pai_config || !pai ||
 538	    pai < pc->min_pai || pai > pc->max_pai)
 539		return -EINVAL;
 540
 541	if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
 542		struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
 543
 544		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
 545				   domain_id, pai, 0);
 546		iowrite32(pai, fci->set_addr);
 547		ph->hops->fastchannel_db_ring(fci->set_db);
 548		return 0;
 549	}
 550
 551	return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
 552}
 553
 554static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
 555					  u32 domain_id, u32 *average_power,
 556					  u32 *pai)
 557{
 558	int ret;
 559	struct scmi_xfer *t;
 560	struct scmi_msg_resp_powercap_meas_get *resp;
 561	const struct scmi_powercap_info *pc;
 562
 563	pc = scmi_powercap_dom_info_get(ph, domain_id);
 564	if (!pc || !pc->powercap_monitoring || !pai || !average_power)
 565		return -EINVAL;
 566
 567	ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
 568				      sizeof(u32), sizeof(*resp), &t);
 569	if (ret)
 570		return ret;
 571
 572	resp = t->rx.buf;
 573	put_unaligned_le32(domain_id, t->tx.buf);
 574	ret = ph->xops->do_xfer(ph, t);
 575	if (!ret) {
 576		*average_power = le32_to_cpu(resp->power);
 577		*pai = le32_to_cpu(resp->pai);
 578	}
 579
 580	ph->xops->xfer_put(ph, t);
 581	return ret;
 582}
 583
 584static int
 585scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
 586					 u32 domain_id, u32 *power_thresh_low,
 587					 u32 *power_thresh_high)
 588{
 589	struct powercap_info *pi = ph->get_priv(ph);
 590
 591	if (!power_thresh_low || !power_thresh_high ||
 592	    domain_id >= pi->num_domains)
 593		return -EINVAL;
 594
 595	*power_thresh_low =  THRESH_LOW(pi, domain_id);
 596	*power_thresh_high = THRESH_HIGH(pi, domain_id);
 597
 598	return 0;
 599}
 600
 601static int
 602scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
 603					 u32 domain_id, u32 power_thresh_low,
 604					 u32 power_thresh_high)
 605{
 606	int ret = 0;
 607	struct powercap_info *pi = ph->get_priv(ph);
 608
 609	if (domain_id >= pi->num_domains ||
 610	    power_thresh_low > power_thresh_high)
 611		return -EINVAL;
 612
 613	/* Anything to do ? */
 614	if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
 615	    THRESH_HIGH(pi, domain_id) == power_thresh_high)
 616		return ret;
 617
 618	pi->states[domain_id].thresholds =
 619		(FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low) |
 620		 FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high));
 621
 622	/* Update thresholds if notification already enabled */
 623	if (pi->states[domain_id].meas_notif_enabled)
 624		ret = scmi_powercap_notify(ph, domain_id,
 625					   POWERCAP_MEASUREMENTS_NOTIFY,
 626					   true);
 627
 628	return ret;
 629}
 630
 631static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
 632					u32 domain_id, bool enable)
 633{
 634	int ret;
 635	u32 power_cap;
 636	struct powercap_info *pi = ph->get_priv(ph);
 637
 638	if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
 639		return -EINVAL;
 640
 641	if (enable == pi->states[domain_id].enabled)
 642		return 0;
 643
 644	if (enable) {
 645		/* Cannot enable with a zero powercap. */
 646		if (!pi->states[domain_id].last_pcap)
 647			return -EINVAL;
 648
 649		ret = __scmi_powercap_cap_set(ph, pi, domain_id,
 650					      pi->states[domain_id].last_pcap,
 651					      true);
 652	} else {
 653		ret = __scmi_powercap_cap_set(ph, pi, domain_id, 0, true);
 654	}
 655
 656	if (ret)
 657		return ret;
 658
 659	/*
 660	 * Update our internal state to reflect final platform state: the SCMI
 661	 * server could have ignored a disable request and kept enforcing some
 662	 * powercap limit requested by other agents.
 663	 */
 664	ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
 665	if (!ret)
 666		pi->states[domain_id].enabled = !!power_cap;
 667
 668	return ret;
 669}
 670
 671static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
 672					u32 domain_id, bool *enable)
 673{
 674	int ret;
 675	u32 power_cap;
 676	struct powercap_info *pi = ph->get_priv(ph);
 677
 678	*enable = true;
 679	if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
 680		return 0;
 681
 682	/*
 683	 * Report always real platform state; platform could have ignored
 684	 * a previous disable request. Default true on any error.
 685	 */
 686	ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
 687	if (!ret)
 688		*enable = !!power_cap;
 689
 690	/* Update internal state with current real platform state */
 691	pi->states[domain_id].enabled = *enable;
 692
 693	return 0;
 694}
 695
 696static const struct scmi_powercap_proto_ops powercap_proto_ops = {
 697	.num_domains_get = scmi_powercap_num_domains_get,
 698	.info_get = scmi_powercap_dom_info_get,
 699	.cap_get = scmi_powercap_cap_get,
 700	.cap_set = scmi_powercap_cap_set,
 701	.cap_enable_set = scmi_powercap_cap_enable_set,
 702	.cap_enable_get = scmi_powercap_cap_enable_get,
 703	.pai_get = scmi_powercap_pai_get,
 704	.pai_set = scmi_powercap_pai_set,
 705	.measurements_get = scmi_powercap_measurements_get,
 706	.measurements_threshold_set = scmi_powercap_measurements_threshold_set,
 707	.measurements_threshold_get = scmi_powercap_measurements_threshold_get,
 708};
 709
 710static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
 711					 u32 domain, struct scmi_fc_info **p_fc)
 712{
 713	struct scmi_fc_info *fc;
 714
 715	fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
 716	if (!fc)
 717		return;
 718
 719	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
 720				   POWERCAP_CAP_SET, 4, domain,
 721				   &fc[POWERCAP_FC_CAP].set_addr,
 722				   &fc[POWERCAP_FC_CAP].set_db,
 723				   &fc[POWERCAP_FC_CAP].rate_limit);
 724
 725	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
 726				   POWERCAP_CAP_GET, 4, domain,
 727				   &fc[POWERCAP_FC_CAP].get_addr, NULL,
 728				   &fc[POWERCAP_FC_CAP].rate_limit);
 729
 730	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
 731				   POWERCAP_PAI_SET, 4, domain,
 732				   &fc[POWERCAP_FC_PAI].set_addr,
 733				   &fc[POWERCAP_FC_PAI].set_db,
 734				   &fc[POWERCAP_FC_PAI].rate_limit);
 735
 736	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
 737				   POWERCAP_PAI_GET, 4, domain,
 738				   &fc[POWERCAP_FC_PAI].get_addr, NULL,
 739				   &fc[POWERCAP_FC_PAI].rate_limit);
 740
 741	*p_fc = fc;
 742}
 743
 744static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
 745				u32 domain, int message_id, bool enable)
 746{
 747	int ret;
 748	struct scmi_xfer *t;
 749
 750	switch (message_id) {
 751	case POWERCAP_CAP_NOTIFY:
 752	{
 753		struct scmi_msg_powercap_notify_cap *notify;
 754
 755		ret = ph->xops->xfer_get_init(ph, message_id,
 756					      sizeof(*notify), 0, &t);
 757		if (ret)
 758			return ret;
 759
 760		notify = t->tx.buf;
 761		notify->domain = cpu_to_le32(domain);
 762		notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
 763		break;
 764	}
 765	case POWERCAP_MEASUREMENTS_NOTIFY:
 766	{
 767		u32 low, high;
 768		struct scmi_msg_powercap_notify_thresh *notify;
 769
 770		/*
 771		 * Note that we have to pick the most recently configured
 772		 * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
 773		 * enable request and we fail, complaining, if no thresholds
 774		 * were ever set, since this is an indication the API has been
 775		 * used wrongly.
 776		 */
 777		ret = scmi_powercap_measurements_threshold_get(ph, domain,
 778							       &low, &high);
 779		if (ret)
 780			return ret;
 781
 782		if (enable && !low && !high) {
 783			dev_err(ph->dev,
 784				"Invalid Measurements Notify thresholds: %u/%u\n",
 785				low, high);
 786			return -EINVAL;
 787		}
 788
 789		ret = ph->xops->xfer_get_init(ph, message_id,
 790					      sizeof(*notify), 0, &t);
 791		if (ret)
 792			return ret;
 793
 794		notify = t->tx.buf;
 795		notify->domain = cpu_to_le32(domain);
 796		notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
 797		notify->power_thresh_low = cpu_to_le32(low);
 798		notify->power_thresh_high = cpu_to_le32(high);
 799		break;
 800	}
 801	default:
 802		return -EINVAL;
 803	}
 804
 805	ret = ph->xops->do_xfer(ph, t);
 806
 807	ph->xops->xfer_put(ph, t);
 808	return ret;
 809}
 810
 811static bool
 812scmi_powercap_notify_supported(const struct scmi_protocol_handle *ph,
 813			       u8 evt_id, u32 src_id)
 814{
 815	bool supported = false;
 816	const struct scmi_powercap_info *dom_info;
 817	struct powercap_info *pi = ph->get_priv(ph);
 818
 819	if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
 820		return false;
 821
 822	dom_info = pi->powercaps + src_id;
 823	if (evt_id == SCMI_EVENT_POWERCAP_CAP_CHANGED)
 824		supported = dom_info->notify_powercap_cap_change;
 825	else if (evt_id == SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED)
 826		supported = dom_info->notify_powercap_measurement_change;
 827
 828	return supported;
 829}
 830
 831static int
 832scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
 833				 u8 evt_id, u32 src_id, bool enable)
 834{
 835	int ret, cmd_id;
 836	struct powercap_info *pi = ph->get_priv(ph);
 837
 838	if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
 839		return -EINVAL;
 840
 841	cmd_id = evt_2_cmd[evt_id];
 842	ret = scmi_powercap_notify(ph, src_id, cmd_id, enable);
 843	if (ret)
 844		pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
 845			 evt_id, src_id, ret);
 846	else if (cmd_id == POWERCAP_MEASUREMENTS_NOTIFY)
 847		/*
 848		 * On success save the current notification enabled state, so
 849		 * as to be able to properly update the notification thresholds
 850		 * when they are modified on a domain for which measurement
 851		 * notifications were currently enabled.
 852		 *
 853		 * This is needed because the SCMI Notification core machinery
 854		 * and API does not support passing per-notification custom
 855		 * arguments at callback registration time.
 856		 *
 857		 * Note that this can be done here with a simple flag since the
 858		 * SCMI core Notifications code takes care of keeping proper
 859		 * per-domain enables refcounting, so that this helper function
 860		 * will be called only once (for enables) when the first user
 861		 * registers a callback on this domain and once more (disable)
 862		 * when the last user de-registers its callback.
 863		 */
 864		pi->states[src_id].meas_notif_enabled = enable;
 865
 866	return ret;
 867}
 868
 869static void *
 870scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
 871				 u8 evt_id, ktime_t timestamp,
 872				 const void *payld, size_t payld_sz,
 873				 void *report, u32 *src_id)
 874{
 875	void *rep = NULL;
 876
 877	switch (evt_id) {
 878	case SCMI_EVENT_POWERCAP_CAP_CHANGED:
 879	{
 880		const struct scmi_powercap_cap_changed_notify_payld *p = payld;
 881		struct scmi_powercap_cap_changed_report *r = report;
 882
 883		if (sizeof(*p) != payld_sz)
 884			break;
 885
 886		r->timestamp = timestamp;
 887		r->agent_id = le32_to_cpu(p->agent_id);
 888		r->domain_id = le32_to_cpu(p->domain_id);
 889		r->power_cap = le32_to_cpu(p->power_cap);
 890		r->pai = le32_to_cpu(p->pai);
 891		*src_id = r->domain_id;
 892		rep = r;
 893		break;
 894	}
 895	case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
 896	{
 897		const struct scmi_powercap_meas_changed_notify_payld *p = payld;
 898		struct scmi_powercap_meas_changed_report *r = report;
 899
 900		if (sizeof(*p) != payld_sz)
 901			break;
 902
 903		r->timestamp = timestamp;
 904		r->agent_id = le32_to_cpu(p->agent_id);
 905		r->domain_id = le32_to_cpu(p->domain_id);
 906		r->power = le32_to_cpu(p->power);
 907		*src_id = r->domain_id;
 908		rep = r;
 909		break;
 910	}
 911	default:
 912		break;
 913	}
 914
 915	return rep;
 916}
 917
 918static int
 919scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
 920{
 921	struct powercap_info *pi = ph->get_priv(ph);
 922
 923	if (!pi)
 924		return -EINVAL;
 925
 926	return pi->num_domains;
 927}
 928
 929static const struct scmi_event powercap_events[] = {
 930	{
 931		.id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
 932		.max_payld_sz =
 933			sizeof(struct scmi_powercap_cap_changed_notify_payld),
 934		.max_report_sz =
 935			sizeof(struct scmi_powercap_cap_changed_report),
 936	},
 937	{
 938		.id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
 939		.max_payld_sz =
 940			sizeof(struct scmi_powercap_meas_changed_notify_payld),
 941		.max_report_sz =
 942			sizeof(struct scmi_powercap_meas_changed_report),
 943	},
 944};
 945
 946static const struct scmi_event_ops powercap_event_ops = {
 947	.is_notify_supported = scmi_powercap_notify_supported,
 948	.get_num_sources = scmi_powercap_get_num_sources,
 949	.set_notify_enabled = scmi_powercap_set_notify_enabled,
 950	.fill_custom_report = scmi_powercap_fill_custom_report,
 951};
 952
 953static const struct scmi_protocol_events powercap_protocol_events = {
 954	.queue_sz = SCMI_PROTO_QUEUE_SZ,
 955	.ops = &powercap_event_ops,
 956	.evts = powercap_events,
 957	.num_events = ARRAY_SIZE(powercap_events),
 958};
 959
 960static int
 961scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 962{
 963	int domain, ret;
 964	u32 version;
 965	struct powercap_info *pinfo;
 966
 967	ret = ph->xops->version_get(ph, &version);
 968	if (ret)
 969		return ret;
 970
 971	dev_dbg(ph->dev, "Powercap Version %d.%d\n",
 972		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
 973
 974	pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
 975	if (!pinfo)
 976		return -ENOMEM;
 977
 978	ret = scmi_powercap_attributes_get(ph, pinfo);
 979	if (ret)
 980		return ret;
 981
 982	pinfo->powercaps = devm_kcalloc(ph->dev, pinfo->num_domains,
 983					sizeof(*pinfo->powercaps),
 984					GFP_KERNEL);
 985	if (!pinfo->powercaps)
 986		return -ENOMEM;
 987
 988	pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
 989				     sizeof(*pinfo->states), GFP_KERNEL);
 990	if (!pinfo->states)
 991		return -ENOMEM;
 992
 993	/*
 994	 * Note that any failure in retrieving any domain attribute leads to
 995	 * the whole Powercap protocol initialization failure: this way the
 996	 * reported Powercap domains are all assured, when accessed, to be well
 997	 * formed and correlated by sane parent-child relationship (if any).
 998	 */
 999	for (domain = 0; domain < pinfo->num_domains; domain++) {
1000		ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
1001		if (ret)
1002			return ret;
1003
1004		if (pinfo->powercaps[domain].fastchannels)
1005			scmi_powercap_domain_init_fc(ph, domain,
1006						     &pinfo->powercaps[domain].fc_info);
1007
1008		/* Grab initial state when disable is supported. */
1009		if (PROTOCOL_REV_MAJOR(version) >= 0x2) {
1010			ret = __scmi_powercap_cap_get(ph,
1011						      &pinfo->powercaps[domain],
1012						      &pinfo->states[domain].last_pcap);
1013			if (ret)
1014				return ret;
1015
1016			pinfo->states[domain].enabled =
1017				!!pinfo->states[domain].last_pcap;
1018		}
1019	}
1020
1021	pinfo->version = version;
1022	return ph->set_priv(ph, pinfo, version);
1023}
1024
1025static const struct scmi_protocol scmi_powercap = {
1026	.id = SCMI_PROTOCOL_POWERCAP,
1027	.owner = THIS_MODULE,
1028	.instance_init = &scmi_powercap_protocol_init,
1029	.ops = &powercap_proto_ops,
1030	.events = &powercap_protocol_events,
1031	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
1032};
1033
1034DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
~/ Read-only file preview.