blob: 6730f965b3793f25ba73125a00b18f346decf75f [file] [log] [blame]
Ashwin Chaugule337aadf2015-10-02 10:01:19 -04001/*
2 * CPPC (Collaborative Processor Performance Control) methods used by CPUfreq drivers.
3 *
4 * (C) Copyright 2014, 2015 Linaro Ltd.
5 * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; version 2
10 * of the License.
11 *
12 * CPPC describes a few methods for controlling CPU performance using
13 * information from a per CPU table called CPC. This table is described in
14 * the ACPI v5.0+ specification. The table consists of a list of
15 * registers which may be memory mapped or hardware registers and also may
16 * include some static integer values.
17 *
18 * CPU performance is on an abstract continuous scale as against a discretized
19 * P-state scale which is tied to CPU frequency only. In brief, the basic
20 * operation involves:
21 *
22 * - OS makes a CPU performance request. (Can provide min and max bounds)
23 *
24 * - Platform (such as BMC) is free to optimize request within requested bounds
25 * depending on power/thermal budgets etc.
26 *
27 * - Platform conveys its decision back to OS
28 *
29 * The communication between OS and platform occurs through another medium
30 * called (PCC) Platform Communication Channel. This is a generic mailbox like
31 * mechanism which includes doorbell semantics to indicate register updates.
32 * See drivers/mailbox/pcc.c for details on PCC.
33 *
34 * Finer details about the PCC and CPPC spec are available in the ACPI v5.1 and
35 * above specifications.
36 */
37
38#define pr_fmt(fmt) "ACPI CPPC: " fmt
39
40#include <linux/cpufreq.h>
41#include <linux/delay.h>
42
43#include <acpi/cppc_acpi.h>
44/*
45 * Lock to provide mutually exclusive access to the PCC
46 * channel. e.g. When the remote updates the shared region
47 * with new data, the reader needs to be protected from
48 * other CPUs activity on the same channel.
49 */
50static DEFINE_SPINLOCK(pcc_lock);
51
52/*
53 * The cpc_desc structure contains the ACPI register details
54 * as described in the per CPU _CPC tables. The details
55 * include the type of register (e.g. PCC, System IO, FFH etc.)
56 * and destination addresses which lets us READ/WRITE CPU performance
57 * information using the appropriate I/O methods.
58 */
59static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
60
61/* This layer handles all the PCC specifics for CPPC. */
62static struct mbox_chan *pcc_channel;
63static void __iomem *pcc_comm_addr;
64static u64 comm_base_addr;
65static int pcc_subspace_idx = -1;
66static u16 pcc_cmd_delay;
67static bool pcc_channel_acquired;
68
69/*
70 * Arbitrary Retries in case the remote processor is slow to respond
71 * to PCC commands.
72 */
73#define NUM_RETRIES 500
74
75static int send_pcc_cmd(u16 cmd)
76{
77 int retries, result = -EIO;
78 struct acpi_pcct_hw_reduced *pcct_ss = pcc_channel->con_priv;
79 struct acpi_pcct_shared_memory *generic_comm_base =
80 (struct acpi_pcct_shared_memory *) pcc_comm_addr;
81 u32 cmd_latency = pcct_ss->latency;
82
83 /* Min time OS should wait before sending next command. */
84 udelay(pcc_cmd_delay);
85
86 /* Write to the shared comm region. */
87 writew(cmd, &generic_comm_base->command);
88
89 /* Flip CMD COMPLETE bit */
90 writew(0, &generic_comm_base->status);
91
92 /* Ring doorbell */
93 result = mbox_send_message(pcc_channel, &cmd);
94 if (result < 0) {
95 pr_err("Err sending PCC mbox message. cmd:%d, ret:%d\n",
96 cmd, result);
97 return result;
98 }
99
100 /* Wait for a nominal time to let platform process command. */
101 udelay(cmd_latency);
102
103 /* Retry in case the remote processor was too slow to catch up. */
104 for (retries = NUM_RETRIES; retries > 0; retries--) {
105 if (readw_relaxed(&generic_comm_base->status) & PCC_CMD_COMPLETE) {
106 result = 0;
107 break;
108 }
109 }
110
111 mbox_client_txdone(pcc_channel, result);
112 return result;
113}
114
115static void cppc_chan_tx_done(struct mbox_client *cl, void *msg, int ret)
116{
117 if (ret)
118 pr_debug("TX did not complete: CMD sent:%x, ret:%d\n",
119 *(u16 *)msg, ret);
120 else
121 pr_debug("TX completed. CMD sent:%x, ret:%d\n",
122 *(u16 *)msg, ret);
123}
124
125struct mbox_client cppc_mbox_cl = {
126 .tx_done = cppc_chan_tx_done,
127 .knows_txdone = true,
128};
129
130static int acpi_get_psd(struct cpc_desc *cpc_ptr, acpi_handle handle)
131{
132 int result = -EFAULT;
133 acpi_status status = AE_OK;
134 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
135 struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
136 struct acpi_buffer state = {0, NULL};
137 union acpi_object *psd = NULL;
138 struct acpi_psd_package *pdomain;
139
140 status = acpi_evaluate_object_typed(handle, "_PSD", NULL, &buffer,
141 ACPI_TYPE_PACKAGE);
142 if (ACPI_FAILURE(status))
143 return -ENODEV;
144
145 psd = buffer.pointer;
146 if (!psd || psd->package.count != 1) {
147 pr_debug("Invalid _PSD data\n");
148 goto end;
149 }
150
151 pdomain = &(cpc_ptr->domain_info);
152
153 state.length = sizeof(struct acpi_psd_package);
154 state.pointer = pdomain;
155
156 status = acpi_extract_package(&(psd->package.elements[0]),
157 &format, &state);
158 if (ACPI_FAILURE(status)) {
159 pr_debug("Invalid _PSD data for CPU:%d\n", cpc_ptr->cpu_id);
160 goto end;
161 }
162
163 if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
164 pr_debug("Unknown _PSD:num_entries for CPU:%d\n", cpc_ptr->cpu_id);
165 goto end;
166 }
167
168 if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
169 pr_debug("Unknown _PSD:revision for CPU: %d\n", cpc_ptr->cpu_id);
170 goto end;
171 }
172
173 if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
174 pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
175 pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
176 pr_debug("Invalid _PSD:coord_type for CPU:%d\n", cpc_ptr->cpu_id);
177 goto end;
178 }
179
180 result = 0;
181end:
182 kfree(buffer.pointer);
183 return result;
184}
185
186/**
187 * acpi_get_psd_map - Map the CPUs in a common freq domain.
188 * @all_cpu_data: Ptrs to CPU specific CPPC data including PSD info.
189 *
190 * Return: 0 for success or negative value for err.
191 */
192int acpi_get_psd_map(struct cpudata **all_cpu_data)
193{
194 int count_target;
195 int retval = 0;
196 unsigned int i, j;
197 cpumask_var_t covered_cpus;
198 struct cpudata *pr, *match_pr;
199 struct acpi_psd_package *pdomain;
200 struct acpi_psd_package *match_pdomain;
201 struct cpc_desc *cpc_ptr, *match_cpc_ptr;
202
203 if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
204 return -ENOMEM;
205
206 /*
207 * Now that we have _PSD data from all CPUs, lets setup P-state
208 * domain info.
209 */
210 for_each_possible_cpu(i) {
211 pr = all_cpu_data[i];
212 if (!pr)
213 continue;
214
215 if (cpumask_test_cpu(i, covered_cpus))
216 continue;
217
218 cpc_ptr = per_cpu(cpc_desc_ptr, i);
219 if (!cpc_ptr)
220 continue;
221
222 pdomain = &(cpc_ptr->domain_info);
223 cpumask_set_cpu(i, pr->shared_cpu_map);
224 cpumask_set_cpu(i, covered_cpus);
225 if (pdomain->num_processors <= 1)
226 continue;
227
228 /* Validate the Domain info */
229 count_target = pdomain->num_processors;
230 if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
231 pr->shared_type = CPUFREQ_SHARED_TYPE_ALL;
232 else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
233 pr->shared_type = CPUFREQ_SHARED_TYPE_HW;
234 else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
235 pr->shared_type = CPUFREQ_SHARED_TYPE_ANY;
236
237 for_each_possible_cpu(j) {
238 if (i == j)
239 continue;
240
241 match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
242 if (!match_cpc_ptr)
243 continue;
244
245 match_pdomain = &(match_cpc_ptr->domain_info);
246 if (match_pdomain->domain != pdomain->domain)
247 continue;
248
249 /* Here i and j are in the same domain */
250 if (match_pdomain->num_processors != count_target) {
251 retval = -EFAULT;
252 goto err_ret;
253 }
254
255 if (pdomain->coord_type != match_pdomain->coord_type) {
256 retval = -EFAULT;
257 goto err_ret;
258 }
259
260 cpumask_set_cpu(j, covered_cpus);
261 cpumask_set_cpu(j, pr->shared_cpu_map);
262 }
263
264 for_each_possible_cpu(j) {
265 if (i == j)
266 continue;
267
268 match_pr = all_cpu_data[j];
269 if (!match_pr)
270 continue;
271
272 match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
273 if (!match_cpc_ptr)
274 continue;
275
276 match_pdomain = &(match_cpc_ptr->domain_info);
277 if (match_pdomain->domain != pdomain->domain)
278 continue;
279
280 match_pr->shared_type = pr->shared_type;
281 cpumask_copy(match_pr->shared_cpu_map,
282 pr->shared_cpu_map);
283 }
284 }
285
286err_ret:
287 for_each_possible_cpu(i) {
288 pr = all_cpu_data[i];
289 if (!pr)
290 continue;
291
292 /* Assume no coordination on any error parsing domain info */
293 if (retval) {
294 cpumask_clear(pr->shared_cpu_map);
295 cpumask_set_cpu(i, pr->shared_cpu_map);
296 pr->shared_type = CPUFREQ_SHARED_TYPE_ALL;
297 }
298 }
299
300 free_cpumask_var(covered_cpus);
301 return retval;
302}
303EXPORT_SYMBOL_GPL(acpi_get_psd_map);
304
Dan Carpenter32c0b2f2015-10-22 22:52:59 +0300305static int register_pcc_channel(int pcc_subspace_idx)
Ashwin Chaugule337aadf2015-10-02 10:01:19 -0400306{
Ashwin Chauguled29d6732015-11-12 19:52:30 -0500307 struct acpi_pcct_hw_reduced *cppc_ss;
Ashwin Chaugule337aadf2015-10-02 10:01:19 -0400308 unsigned int len;
309
310 if (pcc_subspace_idx >= 0) {
311 pcc_channel = pcc_mbox_request_channel(&cppc_mbox_cl,
312 pcc_subspace_idx);
313
314 if (IS_ERR(pcc_channel)) {
315 pr_err("Failed to find PCC communication channel\n");
316 return -ENODEV;
317 }
318
319 /*
320 * The PCC mailbox controller driver should
321 * have parsed the PCCT (global table of all
322 * PCC channels) and stored pointers to the
323 * subspace communication region in con_priv.
324 */
325 cppc_ss = pcc_channel->con_priv;
326
327 if (!cppc_ss) {
328 pr_err("No PCC subspace found for CPPC\n");
329 return -ENODEV;
330 }
331
332 /*
333 * This is the shared communication region
334 * for the OS and Platform to communicate over.
335 */
336 comm_base_addr = cppc_ss->base_address;
337 len = cppc_ss->length;
338 pcc_cmd_delay = cppc_ss->min_turnaround_time;
339
340 pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len);
341 if (!pcc_comm_addr) {
342 pr_err("Failed to ioremap PCC comm region mem\n");
343 return -ENOMEM;
344 }
345
346 /* Set flag so that we dont come here for each CPU. */
347 pcc_channel_acquired = true;
348 }
349
350 return 0;
351}
352
353/*
354 * An example CPC table looks like the following.
355 *
356 * Name(_CPC, Package()
357 * {
358 * 17,
359 * NumEntries
360 * 1,
361 * // Revision
362 * ResourceTemplate(){Register(PCC, 32, 0, 0x120, 2)},
363 * // Highest Performance
364 * ResourceTemplate(){Register(PCC, 32, 0, 0x124, 2)},
365 * // Nominal Performance
366 * ResourceTemplate(){Register(PCC, 32, 0, 0x128, 2)},
367 * // Lowest Nonlinear Performance
368 * ResourceTemplate(){Register(PCC, 32, 0, 0x12C, 2)},
369 * // Lowest Performance
370 * ResourceTemplate(){Register(PCC, 32, 0, 0x130, 2)},
371 * // Guaranteed Performance Register
372 * ResourceTemplate(){Register(PCC, 32, 0, 0x110, 2)},
373 * // Desired Performance Register
374 * ResourceTemplate(){Register(SystemMemory, 0, 0, 0, 0)},
375 * ..
376 * ..
377 * ..
378 *
379 * }
380 * Each Register() encodes how to access that specific register.
381 * e.g. a sample PCC entry has the following encoding:
382 *
383 * Register (
384 * PCC,
385 * AddressSpaceKeyword
386 * 8,
387 * //RegisterBitWidth
388 * 8,
389 * //RegisterBitOffset
390 * 0x30,
391 * //RegisterAddress
392 * 9
393 * //AccessSize (subspace ID)
394 * 0
395 * )
396 * }
397 */
398
399/**
400 * acpi_cppc_processor_probe - Search for per CPU _CPC objects.
401 * @pr: Ptr to acpi_processor containing this CPUs logical Id.
402 *
403 * Return: 0 for success or negative value for err.
404 */
405int acpi_cppc_processor_probe(struct acpi_processor *pr)
406{
407 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
408 union acpi_object *out_obj, *cpc_obj;
409 struct cpc_desc *cpc_ptr;
410 struct cpc_reg *gas_t;
411 acpi_handle handle = pr->handle;
412 unsigned int num_ent, i, cpc_rev;
413 acpi_status status;
414 int ret = -EFAULT;
415
416 /* Parse the ACPI _CPC table for this cpu. */
417 status = acpi_evaluate_object_typed(handle, "_CPC", NULL, &output,
418 ACPI_TYPE_PACKAGE);
419 if (ACPI_FAILURE(status)) {
420 ret = -ENODEV;
421 goto out_buf_free;
422 }
423
424 out_obj = (union acpi_object *) output.pointer;
425
426 cpc_ptr = kzalloc(sizeof(struct cpc_desc), GFP_KERNEL);
427 if (!cpc_ptr) {
428 ret = -ENOMEM;
429 goto out_buf_free;
430 }
431
432 /* First entry is NumEntries. */
433 cpc_obj = &out_obj->package.elements[0];
434 if (cpc_obj->type == ACPI_TYPE_INTEGER) {
435 num_ent = cpc_obj->integer.value;
436 } else {
437 pr_debug("Unexpected entry type(%d) for NumEntries\n",
438 cpc_obj->type);
439 goto out_free;
440 }
441
442 /* Only support CPPCv2. Bail otherwise. */
443 if (num_ent != CPPC_NUM_ENT) {
444 pr_debug("Firmware exports %d entries. Expected: %d\n",
445 num_ent, CPPC_NUM_ENT);
446 goto out_free;
447 }
448
449 /* Second entry should be revision. */
450 cpc_obj = &out_obj->package.elements[1];
451 if (cpc_obj->type == ACPI_TYPE_INTEGER) {
452 cpc_rev = cpc_obj->integer.value;
453 } else {
454 pr_debug("Unexpected entry type(%d) for Revision\n",
455 cpc_obj->type);
456 goto out_free;
457 }
458
459 if (cpc_rev != CPPC_REV) {
460 pr_debug("Firmware exports revision:%d. Expected:%d\n",
461 cpc_rev, CPPC_REV);
462 goto out_free;
463 }
464
465 /* Iterate through remaining entries in _CPC */
466 for (i = 2; i < num_ent; i++) {
467 cpc_obj = &out_obj->package.elements[i];
468
469 if (cpc_obj->type == ACPI_TYPE_INTEGER) {
470 cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_INTEGER;
471 cpc_ptr->cpc_regs[i-2].cpc_entry.int_value = cpc_obj->integer.value;
472 } else if (cpc_obj->type == ACPI_TYPE_BUFFER) {
473 gas_t = (struct cpc_reg *)
474 cpc_obj->buffer.pointer;
475
476 /*
477 * The PCC Subspace index is encoded inside
478 * the CPC table entries. The same PCC index
479 * will be used for all the PCC entries,
480 * so extract it only once.
481 */
482 if (gas_t->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
483 if (pcc_subspace_idx < 0)
484 pcc_subspace_idx = gas_t->access_width;
485 else if (pcc_subspace_idx != gas_t->access_width) {
486 pr_debug("Mismatched PCC ids.\n");
487 goto out_free;
488 }
489 } else if (gas_t->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
490 /* Support only PCC and SYS MEM type regs */
491 pr_debug("Unsupported register type: %d\n", gas_t->space_id);
492 goto out_free;
493 }
494
495 cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_BUFFER;
496 memcpy(&cpc_ptr->cpc_regs[i-2].cpc_entry.reg, gas_t, sizeof(*gas_t));
497 } else {
498 pr_debug("Err in entry:%d in CPC table of CPU:%d \n", i, pr->id);
499 goto out_free;
500 }
501 }
502 /* Store CPU Logical ID */
503 cpc_ptr->cpu_id = pr->id;
504
505 /* Plug it into this CPUs CPC descriptor. */
506 per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
507
508 /* Parse PSD data for this CPU */
509 ret = acpi_get_psd(cpc_ptr, handle);
510 if (ret)
511 goto out_free;
512
513 /* Register PCC channel once for all CPUs. */
514 if (!pcc_channel_acquired) {
515 ret = register_pcc_channel(pcc_subspace_idx);
516 if (ret)
517 goto out_free;
518 }
519
520 /* Everything looks okay */
521 pr_debug("Parsed CPC struct for CPU: %d\n", pr->id);
522
523 kfree(output.pointer);
524 return 0;
525
526out_free:
Ashwin Chaugule337aadf2015-10-02 10:01:19 -0400527 kfree(cpc_ptr);
528
529out_buf_free:
530 kfree(output.pointer);
531 return ret;
532}
533EXPORT_SYMBOL_GPL(acpi_cppc_processor_probe);
534
535/**
536 * acpi_cppc_processor_exit - Cleanup CPC structs.
537 * @pr: Ptr to acpi_processor containing this CPUs logical Id.
538 *
539 * Return: Void
540 */
541void acpi_cppc_processor_exit(struct acpi_processor *pr)
542{
543 struct cpc_desc *cpc_ptr;
544 cpc_ptr = per_cpu(cpc_desc_ptr, pr->id);
545 kfree(cpc_ptr);
546}
547EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
548
549static u64 get_phys_addr(struct cpc_reg *reg)
550{
551 /* PCC communication addr space begins at byte offset 0x8. */
552 if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
553 return (u64)comm_base_addr + 0x8 + reg->address;
554 else
555 return reg->address;
556}
557
558static void cpc_read(struct cpc_reg *reg, u64 *val)
559{
560 u64 addr = get_phys_addr(reg);
561
562 acpi_os_read_memory((acpi_physical_address)addr,
563 val, reg->bit_width);
564}
565
566static void cpc_write(struct cpc_reg *reg, u64 val)
567{
568 u64 addr = get_phys_addr(reg);
569
570 acpi_os_write_memory((acpi_physical_address)addr,
571 val, reg->bit_width);
572}
573
574/**
575 * cppc_get_perf_caps - Get a CPUs performance capabilities.
576 * @cpunum: CPU from which to get capabilities info.
577 * @perf_caps: ptr to cppc_perf_caps. See cppc_acpi.h
578 *
579 * Return: 0 for success with perf_caps populated else -ERRNO.
580 */
581int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
582{
583 struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
584 struct cpc_register_resource *highest_reg, *lowest_reg, *ref_perf,
585 *nom_perf;
586 u64 high, low, ref, nom;
587 int ret = 0;
588
589 if (!cpc_desc) {
590 pr_debug("No CPC descriptor for CPU:%d\n", cpunum);
591 return -ENODEV;
592 }
593
594 highest_reg = &cpc_desc->cpc_regs[HIGHEST_PERF];
595 lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF];
596 ref_perf = &cpc_desc->cpc_regs[REFERENCE_PERF];
597 nom_perf = &cpc_desc->cpc_regs[NOMINAL_PERF];
598
599 spin_lock(&pcc_lock);
600
601 /* Are any of the regs PCC ?*/
602 if ((highest_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
603 (lowest_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
604 (ref_perf->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
605 (nom_perf->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) {
606 /* Ring doorbell once to update PCC subspace */
607 if (send_pcc_cmd(CMD_READ)) {
608 ret = -EIO;
609 goto out_err;
610 }
611 }
612
613 cpc_read(&highest_reg->cpc_entry.reg, &high);
614 perf_caps->highest_perf = high;
615
616 cpc_read(&lowest_reg->cpc_entry.reg, &low);
617 perf_caps->lowest_perf = low;
618
619 cpc_read(&ref_perf->cpc_entry.reg, &ref);
620 perf_caps->reference_perf = ref;
621
622 cpc_read(&nom_perf->cpc_entry.reg, &nom);
623 perf_caps->nominal_perf = nom;
624
625 if (!ref)
626 perf_caps->reference_perf = perf_caps->nominal_perf;
627
628 if (!high || !low || !nom)
629 ret = -EFAULT;
630
631out_err:
632 spin_unlock(&pcc_lock);
633 return ret;
634}
635EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
636
637/**
638 * cppc_get_perf_ctrs - Read a CPUs performance feedback counters.
639 * @cpunum: CPU from which to read counters.
640 * @perf_fb_ctrs: ptr to cppc_perf_fb_ctrs. See cppc_acpi.h
641 *
642 * Return: 0 for success with perf_fb_ctrs populated else -ERRNO.
643 */
644int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
645{
646 struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
647 struct cpc_register_resource *delivered_reg, *reference_reg;
648 u64 delivered, reference;
649 int ret = 0;
650
651 if (!cpc_desc) {
652 pr_debug("No CPC descriptor for CPU:%d\n", cpunum);
653 return -ENODEV;
654 }
655
656 delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR];
657 reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR];
658
659 spin_lock(&pcc_lock);
660
661 /* Are any of the regs PCC ?*/
662 if ((delivered_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
663 (reference_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) {
664 /* Ring doorbell once to update PCC subspace */
665 if (send_pcc_cmd(CMD_READ)) {
666 ret = -EIO;
667 goto out_err;
668 }
669 }
670
671 cpc_read(&delivered_reg->cpc_entry.reg, &delivered);
672 cpc_read(&reference_reg->cpc_entry.reg, &reference);
673
674 if (!delivered || !reference) {
675 ret = -EFAULT;
676 goto out_err;
677 }
678
679 perf_fb_ctrs->delivered = delivered;
680 perf_fb_ctrs->reference = reference;
681
682 perf_fb_ctrs->delivered -= perf_fb_ctrs->prev_delivered;
683 perf_fb_ctrs->reference -= perf_fb_ctrs->prev_reference;
684
685 perf_fb_ctrs->prev_delivered = delivered;
686 perf_fb_ctrs->prev_reference = reference;
687
688out_err:
689 spin_unlock(&pcc_lock);
690 return ret;
691}
692EXPORT_SYMBOL_GPL(cppc_get_perf_ctrs);
693
694/**
695 * cppc_set_perf - Set a CPUs performance controls.
696 * @cpu: CPU for which to set performance controls.
697 * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h
698 *
699 * Return: 0 for success, -ERRNO otherwise.
700 */
701int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
702{
703 struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
704 struct cpc_register_resource *desired_reg;
705 int ret = 0;
706
707 if (!cpc_desc) {
708 pr_debug("No CPC descriptor for CPU:%d\n", cpu);
709 return -ENODEV;
710 }
711
712 desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF];
713
714 spin_lock(&pcc_lock);
715
716 /*
717 * Skip writing MIN/MAX until Linux knows how to come up with
718 * useful values.
719 */
720 cpc_write(&desired_reg->cpc_entry.reg, perf_ctrls->desired_perf);
721
722 /* Is this a PCC reg ?*/
723 if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
724 /* Ring doorbell so Remote can get our perf request. */
725 if (send_pcc_cmd(CMD_WRITE))
726 ret = -EIO;
727 }
728
729 spin_unlock(&pcc_lock);
730
731 return ret;
732}
733EXPORT_SYMBOL_GPL(cppc_set_perf);