powercap.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  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. #define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
  8. #include <linux/bitfield.h>
  9. #include <linux/io.h>
  10. #include <linux/module.h>
  11. #include <linux/scmi_protocol.h>
  12. #include <trace/events/scmi.h>
  13. #include "protocols.h"
  14. #include "notify.h"
  15. enum scmi_powercap_protocol_cmd {
  16. POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
  17. POWERCAP_CAP_GET = 0x4,
  18. POWERCAP_CAP_SET = 0x5,
  19. POWERCAP_PAI_GET = 0x6,
  20. POWERCAP_PAI_SET = 0x7,
  21. POWERCAP_DOMAIN_NAME_GET = 0x8,
  22. POWERCAP_MEASUREMENTS_GET = 0x9,
  23. POWERCAP_CAP_NOTIFY = 0xa,
  24. POWERCAP_MEASUREMENTS_NOTIFY = 0xb,
  25. POWERCAP_DESCRIBE_FASTCHANNEL = 0xc,
  26. };
  27. enum {
  28. POWERCAP_FC_CAP,
  29. POWERCAP_FC_PAI,
  30. POWERCAP_FC_MAX,
  31. };
  32. struct scmi_msg_resp_powercap_domain_attributes {
  33. __le32 attributes;
  34. #define SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(x) ((x) & BIT(31))
  35. #define SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(x) ((x) & BIT(30))
  36. #define SUPPORTS_ASYNC_POWERCAP_CAP_SET(x) ((x) & BIT(29))
  37. #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(28))
  38. #define SUPPORTS_POWERCAP_CAP_CONFIGURATION(x) ((x) & BIT(27))
  39. #define SUPPORTS_POWERCAP_MONITORING(x) ((x) & BIT(26))
  40. #define SUPPORTS_POWERCAP_PAI_CONFIGURATION(x) ((x) & BIT(25))
  41. #define SUPPORTS_POWERCAP_FASTCHANNELS(x) ((x) & BIT(22))
  42. #define POWERCAP_POWER_UNIT(x) \
  43. (FIELD_GET(GENMASK(24, 23), (x)))
  44. #define SUPPORTS_POWER_UNITS_MW(x) \
  45. (POWERCAP_POWER_UNIT(x) == 0x2)
  46. #define SUPPORTS_POWER_UNITS_UW(x) \
  47. (POWERCAP_POWER_UNIT(x) == 0x1)
  48. u8 name[SCMI_SHORT_NAME_MAX_SIZE];
  49. __le32 min_pai;
  50. __le32 max_pai;
  51. __le32 pai_step;
  52. __le32 min_power_cap;
  53. __le32 max_power_cap;
  54. __le32 power_cap_step;
  55. __le32 sustainable_power;
  56. __le32 accuracy;
  57. __le32 parent_id;
  58. };
  59. struct scmi_msg_powercap_set_cap_or_pai {
  60. __le32 domain;
  61. __le32 flags;
  62. #define CAP_SET_ASYNC BIT(1)
  63. #define CAP_SET_IGNORE_DRESP BIT(0)
  64. __le32 value;
  65. };
  66. struct scmi_msg_resp_powercap_cap_set_complete {
  67. __le32 domain;
  68. __le32 power_cap;
  69. };
  70. struct scmi_msg_resp_powercap_meas_get {
  71. __le32 power;
  72. __le32 pai;
  73. };
  74. struct scmi_msg_powercap_notify_cap {
  75. __le32 domain;
  76. __le32 notify_enable;
  77. };
  78. struct scmi_msg_powercap_notify_thresh {
  79. __le32 domain;
  80. __le32 notify_enable;
  81. __le32 power_thresh_low;
  82. __le32 power_thresh_high;
  83. };
  84. struct scmi_powercap_cap_changed_notify_payld {
  85. __le32 agent_id;
  86. __le32 domain_id;
  87. __le32 power_cap;
  88. __le32 pai;
  89. };
  90. struct scmi_powercap_meas_changed_notify_payld {
  91. __le32 agent_id;
  92. __le32 domain_id;
  93. __le32 power;
  94. };
  95. struct scmi_powercap_state {
  96. bool meas_notif_enabled;
  97. u64 thresholds;
  98. #define THRESH_LOW(p, id) \
  99. (lower_32_bits((p)->states[(id)].thresholds))
  100. #define THRESH_HIGH(p, id) \
  101. (upper_32_bits((p)->states[(id)].thresholds))
  102. };
  103. struct powercap_info {
  104. u32 version;
  105. int num_domains;
  106. struct scmi_powercap_state *states;
  107. struct scmi_powercap_info *powercaps;
  108. };
  109. static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
  110. POWERCAP_CAP_NOTIFY,
  111. POWERCAP_MEASUREMENTS_NOTIFY,
  112. };
  113. static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
  114. u32 domain, int message_id, bool enable);
  115. static int
  116. scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
  117. struct powercap_info *pi)
  118. {
  119. int ret;
  120. struct scmi_xfer *t;
  121. ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
  122. sizeof(u32), &t);
  123. if (ret)
  124. return ret;
  125. ret = ph->xops->do_xfer(ph, t);
  126. if (!ret) {
  127. u32 attributes;
  128. attributes = get_unaligned_le32(t->rx.buf);
  129. pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
  130. }
  131. ph->xops->xfer_put(ph, t);
  132. return ret;
  133. }
  134. static inline int
  135. scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
  136. unsigned int step_val, bool configurable)
  137. {
  138. if (!min_val || !max_val)
  139. return -EPROTO;
  140. if ((configurable && min_val == max_val) ||
  141. (!configurable && min_val != max_val))
  142. return -EPROTO;
  143. if (min_val != max_val && !step_val)
  144. return -EPROTO;
  145. return 0;
  146. }
  147. static int
  148. scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
  149. struct powercap_info *pinfo, u32 domain)
  150. {
  151. int ret;
  152. u32 flags;
  153. struct scmi_xfer *t;
  154. struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
  155. struct scmi_msg_resp_powercap_domain_attributes *resp;
  156. ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
  157. sizeof(domain), sizeof(*resp), &t);
  158. if (ret)
  159. return ret;
  160. put_unaligned_le32(domain, t->tx.buf);
  161. resp = t->rx.buf;
  162. ret = ph->xops->do_xfer(ph, t);
  163. if (!ret) {
  164. flags = le32_to_cpu(resp->attributes);
  165. dom_info->id = domain;
  166. dom_info->notify_powercap_cap_change =
  167. SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
  168. dom_info->notify_powercap_measurement_change =
  169. SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
  170. dom_info->async_powercap_cap_set =
  171. SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
  172. dom_info->powercap_cap_config =
  173. SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
  174. dom_info->powercap_monitoring =
  175. SUPPORTS_POWERCAP_MONITORING(flags);
  176. dom_info->powercap_pai_config =
  177. SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
  178. dom_info->powercap_scale_mw =
  179. SUPPORTS_POWER_UNITS_MW(flags);
  180. dom_info->powercap_scale_uw =
  181. SUPPORTS_POWER_UNITS_UW(flags);
  182. dom_info->fastchannels =
  183. SUPPORTS_POWERCAP_FASTCHANNELS(flags);
  184. strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
  185. dom_info->min_pai = le32_to_cpu(resp->min_pai);
  186. dom_info->max_pai = le32_to_cpu(resp->max_pai);
  187. dom_info->pai_step = le32_to_cpu(resp->pai_step);
  188. ret = scmi_powercap_validate(dom_info->min_pai,
  189. dom_info->max_pai,
  190. dom_info->pai_step,
  191. dom_info->powercap_pai_config);
  192. if (ret) {
  193. dev_err(ph->dev,
  194. "Platform reported inconsistent PAI config for domain %d - %s\n",
  195. dom_info->id, dom_info->name);
  196. goto clean;
  197. }
  198. dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
  199. dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
  200. dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
  201. ret = scmi_powercap_validate(dom_info->min_power_cap,
  202. dom_info->max_power_cap,
  203. dom_info->power_cap_step,
  204. dom_info->powercap_cap_config);
  205. if (ret) {
  206. dev_err(ph->dev,
  207. "Platform reported inconsistent CAP config for domain %d - %s\n",
  208. dom_info->id, dom_info->name);
  209. goto clean;
  210. }
  211. dom_info->sustainable_power =
  212. le32_to_cpu(resp->sustainable_power);
  213. dom_info->accuracy = le32_to_cpu(resp->accuracy);
  214. dom_info->parent_id = le32_to_cpu(resp->parent_id);
  215. if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
  216. (dom_info->parent_id >= pinfo->num_domains ||
  217. dom_info->parent_id == dom_info->id)) {
  218. dev_err(ph->dev,
  219. "Platform reported inconsistent parent ID for domain %d - %s\n",
  220. dom_info->id, dom_info->name);
  221. ret = -ENODEV;
  222. }
  223. }
  224. clean:
  225. ph->xops->xfer_put(ph, t);
  226. /*
  227. * If supported overwrite short name with the extended one;
  228. * on error just carry on and use already provided short name.
  229. */
  230. if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
  231. ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
  232. domain, dom_info->name,
  233. SCMI_MAX_STR_SIZE);
  234. return ret;
  235. }
  236. static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
  237. {
  238. struct powercap_info *pi = ph->get_priv(ph);
  239. return pi->num_domains;
  240. }
  241. static const struct scmi_powercap_info *
  242. scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
  243. {
  244. struct powercap_info *pi = ph->get_priv(ph);
  245. if (domain_id >= pi->num_domains)
  246. return NULL;
  247. return pi->powercaps + domain_id;
  248. }
  249. static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
  250. u32 domain_id, u32 *power_cap)
  251. {
  252. int ret;
  253. struct scmi_xfer *t;
  254. ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
  255. sizeof(u32), &t);
  256. if (ret)
  257. return ret;
  258. put_unaligned_le32(domain_id, t->tx.buf);
  259. ret = ph->xops->do_xfer(ph, t);
  260. if (!ret)
  261. *power_cap = get_unaligned_le32(t->rx.buf);
  262. ph->xops->xfer_put(ph, t);
  263. return ret;
  264. }
  265. static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
  266. u32 domain_id, u32 *power_cap)
  267. {
  268. struct scmi_powercap_info *dom;
  269. struct powercap_info *pi = ph->get_priv(ph);
  270. if (!power_cap || domain_id >= pi->num_domains)
  271. return -EINVAL;
  272. dom = pi->powercaps + domain_id;
  273. if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
  274. *power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
  275. trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
  276. domain_id, *power_cap, 0);
  277. return 0;
  278. }
  279. return scmi_powercap_xfer_cap_get(ph, domain_id, power_cap);
  280. }
  281. static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
  282. const struct scmi_powercap_info *pc,
  283. u32 power_cap, bool ignore_dresp)
  284. {
  285. int ret;
  286. struct scmi_xfer *t;
  287. struct scmi_msg_powercap_set_cap_or_pai *msg;
  288. ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
  289. sizeof(*msg), 0, &t);
  290. if (ret)
  291. return ret;
  292. msg = t->tx.buf;
  293. msg->domain = cpu_to_le32(pc->id);
  294. msg->flags =
  295. cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, !!pc->async_powercap_cap_set) |
  296. FIELD_PREP(CAP_SET_IGNORE_DRESP, !!ignore_dresp));
  297. msg->value = cpu_to_le32(power_cap);
  298. if (!pc->async_powercap_cap_set || ignore_dresp) {
  299. ret = ph->xops->do_xfer(ph, t);
  300. } else {
  301. ret = ph->xops->do_xfer_with_response(ph, t);
  302. if (!ret) {
  303. struct scmi_msg_resp_powercap_cap_set_complete *resp;
  304. resp = t->rx.buf;
  305. if (le32_to_cpu(resp->domain) == pc->id)
  306. dev_dbg(ph->dev,
  307. "Powercap ID %d CAP set async to %u\n",
  308. pc->id,
  309. get_unaligned_le32(&resp->power_cap));
  310. else
  311. ret = -EPROTO;
  312. }
  313. }
  314. ph->xops->xfer_put(ph, t);
  315. return ret;
  316. }
  317. static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
  318. u32 domain_id, u32 power_cap,
  319. bool ignore_dresp)
  320. {
  321. const struct scmi_powercap_info *pc;
  322. pc = scmi_powercap_dom_info_get(ph, domain_id);
  323. if (!pc || !pc->powercap_cap_config || !power_cap ||
  324. power_cap < pc->min_power_cap ||
  325. power_cap > pc->max_power_cap)
  326. return -EINVAL;
  327. if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
  328. struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
  329. iowrite32(power_cap, fci->set_addr);
  330. ph->hops->fastchannel_db_ring(fci->set_db);
  331. trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
  332. domain_id, power_cap, 0);
  333. return 0;
  334. }
  335. return scmi_powercap_xfer_cap_set(ph, pc, power_cap, ignore_dresp);
  336. }
  337. static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
  338. u32 domain_id, u32 *pai)
  339. {
  340. int ret;
  341. struct scmi_xfer *t;
  342. ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
  343. sizeof(u32), &t);
  344. if (ret)
  345. return ret;
  346. put_unaligned_le32(domain_id, t->tx.buf);
  347. ret = ph->xops->do_xfer(ph, t);
  348. if (!ret)
  349. *pai = get_unaligned_le32(t->rx.buf);
  350. ph->xops->xfer_put(ph, t);
  351. return ret;
  352. }
  353. static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
  354. u32 domain_id, u32 *pai)
  355. {
  356. struct scmi_powercap_info *dom;
  357. struct powercap_info *pi = ph->get_priv(ph);
  358. if (!pai || domain_id >= pi->num_domains)
  359. return -EINVAL;
  360. dom = pi->powercaps + domain_id;
  361. if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
  362. *pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
  363. trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
  364. domain_id, *pai, 0);
  365. return 0;
  366. }
  367. return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
  368. }
  369. static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
  370. u32 domain_id, u32 pai)
  371. {
  372. int ret;
  373. struct scmi_xfer *t;
  374. struct scmi_msg_powercap_set_cap_or_pai *msg;
  375. ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
  376. sizeof(*msg), 0, &t);
  377. if (ret)
  378. return ret;
  379. msg = t->tx.buf;
  380. msg->domain = cpu_to_le32(domain_id);
  381. msg->flags = cpu_to_le32(0);
  382. msg->value = cpu_to_le32(pai);
  383. ret = ph->xops->do_xfer(ph, t);
  384. ph->xops->xfer_put(ph, t);
  385. return ret;
  386. }
  387. static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
  388. u32 domain_id, u32 pai)
  389. {
  390. const struct scmi_powercap_info *pc;
  391. pc = scmi_powercap_dom_info_get(ph, domain_id);
  392. if (!pc || !pc->powercap_pai_config || !pai ||
  393. pai < pc->min_pai || pai > pc->max_pai)
  394. return -EINVAL;
  395. if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
  396. struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
  397. trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
  398. domain_id, pai, 0);
  399. iowrite32(pai, fci->set_addr);
  400. ph->hops->fastchannel_db_ring(fci->set_db);
  401. return 0;
  402. }
  403. return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
  404. }
  405. static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
  406. u32 domain_id, u32 *average_power,
  407. u32 *pai)
  408. {
  409. int ret;
  410. struct scmi_xfer *t;
  411. struct scmi_msg_resp_powercap_meas_get *resp;
  412. const struct scmi_powercap_info *pc;
  413. pc = scmi_powercap_dom_info_get(ph, domain_id);
  414. if (!pc || !pc->powercap_monitoring || !pai || !average_power)
  415. return -EINVAL;
  416. ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
  417. sizeof(u32), sizeof(*resp), &t);
  418. if (ret)
  419. return ret;
  420. resp = t->rx.buf;
  421. put_unaligned_le32(domain_id, t->tx.buf);
  422. ret = ph->xops->do_xfer(ph, t);
  423. if (!ret) {
  424. *average_power = le32_to_cpu(resp->power);
  425. *pai = le32_to_cpu(resp->pai);
  426. }
  427. ph->xops->xfer_put(ph, t);
  428. return ret;
  429. }
  430. static int
  431. scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
  432. u32 domain_id, u32 *power_thresh_low,
  433. u32 *power_thresh_high)
  434. {
  435. struct powercap_info *pi = ph->get_priv(ph);
  436. if (!power_thresh_low || !power_thresh_high ||
  437. domain_id >= pi->num_domains)
  438. return -EINVAL;
  439. *power_thresh_low = THRESH_LOW(pi, domain_id);
  440. *power_thresh_high = THRESH_HIGH(pi, domain_id);
  441. return 0;
  442. }
  443. static int
  444. scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
  445. u32 domain_id, u32 power_thresh_low,
  446. u32 power_thresh_high)
  447. {
  448. int ret = 0;
  449. struct powercap_info *pi = ph->get_priv(ph);
  450. if (domain_id >= pi->num_domains ||
  451. power_thresh_low > power_thresh_high)
  452. return -EINVAL;
  453. /* Anything to do ? */
  454. if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
  455. THRESH_HIGH(pi, domain_id) == power_thresh_high)
  456. return ret;
  457. pi->states[domain_id].thresholds =
  458. (FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low) |
  459. FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high));
  460. /* Update thresholds if notification already enabled */
  461. if (pi->states[domain_id].meas_notif_enabled)
  462. ret = scmi_powercap_notify(ph, domain_id,
  463. POWERCAP_MEASUREMENTS_NOTIFY,
  464. true);
  465. return ret;
  466. }
  467. static const struct scmi_powercap_proto_ops powercap_proto_ops = {
  468. .num_domains_get = scmi_powercap_num_domains_get,
  469. .info_get = scmi_powercap_dom_info_get,
  470. .cap_get = scmi_powercap_cap_get,
  471. .cap_set = scmi_powercap_cap_set,
  472. .pai_get = scmi_powercap_pai_get,
  473. .pai_set = scmi_powercap_pai_set,
  474. .measurements_get = scmi_powercap_measurements_get,
  475. .measurements_threshold_set = scmi_powercap_measurements_threshold_set,
  476. .measurements_threshold_get = scmi_powercap_measurements_threshold_get,
  477. };
  478. static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
  479. u32 domain, struct scmi_fc_info **p_fc)
  480. {
  481. struct scmi_fc_info *fc;
  482. fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
  483. if (!fc)
  484. return;
  485. ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
  486. POWERCAP_CAP_SET, 4, domain,
  487. &fc[POWERCAP_FC_CAP].set_addr,
  488. &fc[POWERCAP_FC_CAP].set_db);
  489. ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
  490. POWERCAP_CAP_GET, 4, domain,
  491. &fc[POWERCAP_FC_CAP].get_addr, NULL);
  492. ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
  493. POWERCAP_PAI_SET, 4, domain,
  494. &fc[POWERCAP_FC_PAI].set_addr,
  495. &fc[POWERCAP_FC_PAI].set_db);
  496. ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
  497. POWERCAP_PAI_GET, 4, domain,
  498. &fc[POWERCAP_FC_PAI].get_addr, NULL);
  499. *p_fc = fc;
  500. }
  501. static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
  502. u32 domain, int message_id, bool enable)
  503. {
  504. int ret;
  505. struct scmi_xfer *t;
  506. switch (message_id) {
  507. case POWERCAP_CAP_NOTIFY:
  508. {
  509. struct scmi_msg_powercap_notify_cap *notify;
  510. ret = ph->xops->xfer_get_init(ph, message_id,
  511. sizeof(*notify), 0, &t);
  512. if (ret)
  513. return ret;
  514. notify = t->tx.buf;
  515. notify->domain = cpu_to_le32(domain);
  516. notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
  517. break;
  518. }
  519. case POWERCAP_MEASUREMENTS_NOTIFY:
  520. {
  521. u32 low, high;
  522. struct scmi_msg_powercap_notify_thresh *notify;
  523. /*
  524. * Note that we have to pick the most recently configured
  525. * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
  526. * enable request and we fail, complaining, if no thresholds
  527. * were ever set, since this is an indication the API has been
  528. * used wrongly.
  529. */
  530. ret = scmi_powercap_measurements_threshold_get(ph, domain,
  531. &low, &high);
  532. if (ret)
  533. return ret;
  534. if (enable && !low && !high) {
  535. dev_err(ph->dev,
  536. "Invalid Measurements Notify thresholds: %u/%u\n",
  537. low, high);
  538. return -EINVAL;
  539. }
  540. ret = ph->xops->xfer_get_init(ph, message_id,
  541. sizeof(*notify), 0, &t);
  542. if (ret)
  543. return ret;
  544. notify = t->tx.buf;
  545. notify->domain = cpu_to_le32(domain);
  546. notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
  547. notify->power_thresh_low = cpu_to_le32(low);
  548. notify->power_thresh_high = cpu_to_le32(high);
  549. break;
  550. }
  551. default:
  552. return -EINVAL;
  553. }
  554. ret = ph->xops->do_xfer(ph, t);
  555. ph->xops->xfer_put(ph, t);
  556. return ret;
  557. }
  558. static int
  559. scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
  560. u8 evt_id, u32 src_id, bool enable)
  561. {
  562. int ret, cmd_id;
  563. struct powercap_info *pi = ph->get_priv(ph);
  564. if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
  565. return -EINVAL;
  566. cmd_id = evt_2_cmd[evt_id];
  567. ret = scmi_powercap_notify(ph, src_id, cmd_id, enable);
  568. if (ret)
  569. pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
  570. evt_id, src_id, ret);
  571. else if (cmd_id == POWERCAP_MEASUREMENTS_NOTIFY)
  572. /*
  573. * On success save the current notification enabled state, so
  574. * as to be able to properly update the notification thresholds
  575. * when they are modified on a domain for which measurement
  576. * notifications were currently enabled.
  577. *
  578. * This is needed because the SCMI Notification core machinery
  579. * and API does not support passing per-notification custom
  580. * arguments at callback registration time.
  581. *
  582. * Note that this can be done here with a simple flag since the
  583. * SCMI core Notifications code takes care of keeping proper
  584. * per-domain enables refcounting, so that this helper function
  585. * will be called only once (for enables) when the first user
  586. * registers a callback on this domain and once more (disable)
  587. * when the last user de-registers its callback.
  588. */
  589. pi->states[src_id].meas_notif_enabled = enable;
  590. return ret;
  591. }
  592. static void *
  593. scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
  594. u8 evt_id, ktime_t timestamp,
  595. const void *payld, size_t payld_sz,
  596. void *report, u32 *src_id)
  597. {
  598. void *rep = NULL;
  599. switch (evt_id) {
  600. case SCMI_EVENT_POWERCAP_CAP_CHANGED:
  601. {
  602. const struct scmi_powercap_cap_changed_notify_payld *p = payld;
  603. struct scmi_powercap_cap_changed_report *r = report;
  604. if (sizeof(*p) != payld_sz)
  605. break;
  606. r->timestamp = timestamp;
  607. r->agent_id = le32_to_cpu(p->agent_id);
  608. r->domain_id = le32_to_cpu(p->domain_id);
  609. r->power_cap = le32_to_cpu(p->power_cap);
  610. r->pai = le32_to_cpu(p->pai);
  611. *src_id = r->domain_id;
  612. rep = r;
  613. break;
  614. }
  615. case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
  616. {
  617. const struct scmi_powercap_meas_changed_notify_payld *p = payld;
  618. struct scmi_powercap_meas_changed_report *r = report;
  619. if (sizeof(*p) != payld_sz)
  620. break;
  621. r->timestamp = timestamp;
  622. r->agent_id = le32_to_cpu(p->agent_id);
  623. r->domain_id = le32_to_cpu(p->domain_id);
  624. r->power = le32_to_cpu(p->power);
  625. *src_id = r->domain_id;
  626. rep = r;
  627. break;
  628. }
  629. default:
  630. break;
  631. }
  632. return rep;
  633. }
  634. static int
  635. scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
  636. {
  637. struct powercap_info *pi = ph->get_priv(ph);
  638. if (!pi)
  639. return -EINVAL;
  640. return pi->num_domains;
  641. }
  642. static const struct scmi_event powercap_events[] = {
  643. {
  644. .id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
  645. .max_payld_sz =
  646. sizeof(struct scmi_powercap_cap_changed_notify_payld),
  647. .max_report_sz =
  648. sizeof(struct scmi_powercap_cap_changed_report),
  649. },
  650. {
  651. .id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
  652. .max_payld_sz =
  653. sizeof(struct scmi_powercap_meas_changed_notify_payld),
  654. .max_report_sz =
  655. sizeof(struct scmi_powercap_meas_changed_report),
  656. },
  657. };
  658. static const struct scmi_event_ops powercap_event_ops = {
  659. .get_num_sources = scmi_powercap_get_num_sources,
  660. .set_notify_enabled = scmi_powercap_set_notify_enabled,
  661. .fill_custom_report = scmi_powercap_fill_custom_report,
  662. };
  663. static const struct scmi_protocol_events powercap_protocol_events = {
  664. .queue_sz = SCMI_PROTO_QUEUE_SZ,
  665. .ops = &powercap_event_ops,
  666. .evts = powercap_events,
  667. .num_events = ARRAY_SIZE(powercap_events),
  668. };
  669. static int
  670. scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
  671. {
  672. int domain, ret;
  673. u32 version;
  674. struct powercap_info *pinfo;
  675. ret = ph->xops->version_get(ph, &version);
  676. if (ret)
  677. return ret;
  678. dev_dbg(ph->dev, "Powercap Version %d.%d\n",
  679. PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
  680. pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
  681. if (!pinfo)
  682. return -ENOMEM;
  683. ret = scmi_powercap_attributes_get(ph, pinfo);
  684. if (ret)
  685. return ret;
  686. pinfo->powercaps = devm_kcalloc(ph->dev, pinfo->num_domains,
  687. sizeof(*pinfo->powercaps),
  688. GFP_KERNEL);
  689. if (!pinfo->powercaps)
  690. return -ENOMEM;
  691. /*
  692. * Note that any failure in retrieving any domain attribute leads to
  693. * the whole Powercap protocol initialization failure: this way the
  694. * reported Powercap domains are all assured, when accessed, to be well
  695. * formed and correlated by sane parent-child relationship (if any).
  696. */
  697. for (domain = 0; domain < pinfo->num_domains; domain++) {
  698. ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
  699. if (ret)
  700. return ret;
  701. if (pinfo->powercaps[domain].fastchannels)
  702. scmi_powercap_domain_init_fc(ph, domain,
  703. &pinfo->powercaps[domain].fc_info);
  704. }
  705. pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
  706. sizeof(*pinfo->states), GFP_KERNEL);
  707. if (!pinfo->states)
  708. return -ENOMEM;
  709. pinfo->version = version;
  710. return ph->set_priv(ph, pinfo);
  711. }
  712. static const struct scmi_protocol scmi_powercap = {
  713. .id = SCMI_PROTOCOL_POWERCAP,
  714. .owner = THIS_MODULE,
  715. .instance_init = &scmi_powercap_protocol_init,
  716. .ops = &powercap_proto_ops,
  717. .events = &powercap_protocol_events,
  718. };
  719. DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)