Skip to content

Commit 054e44b

Browse files
Gautham R. Shenoympe
authored andcommitted
cpuidle: pseries: Add function to parse extended CEDE records
Currently we use CEDE with latency-hint 0 as the only other idle state on a dedicated LPAR apart from the polling "snooze" state. The platform might support additional extended CEDE idle states, which can be discovered through the "ibm,get-system-parameter" rtas-call made with CEDE_LATENCY_TOKEN. This patch adds a function to obtain information about the extended CEDE idle states from the platform and parse the contents to populate an array of extended CEDE states. These idle states thus discovered will be added to the cpuidle framework in the next patch. dmesg on a POWER8 and POWER9 LPAR, demonstrating the output of parsing the extended CEDE latency parameters are as follows POWER8 [ 10.093279] xcede : xcede_record_size = 10 [ 10.093285] xcede : Record 0 : hint = 1, latency = 0x3c00 tb ticks, Wake-on-irq = 1 [ 10.093291] xcede : Record 1 : hint = 2, latency = 0x4e2000 tb ticks, Wake-on-irq = 0 [ 10.093297] cpuidle : Skipping the 2 Extended CEDE idle states POWER9 [ 5.913180] xcede : xcede_record_size = 10 [ 5.913183] xcede : Record 0 : hint = 1, latency = 0x400 tb ticks, Wake-on-irq = 1 [ 5.913188] xcede : Record 1 : hint = 2, latency = 0x3e8000 tb ticks, Wake-on-irq = 0 [ 5.913193] cpuidle : Skipping the 2 Extended CEDE idle states Signed-off-by: Gautham R. Shenoy <[email protected]> [mpe: Make space for 16 records, drop memset, minor cleanup & formatting] Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 3af0ada commit 054e44b

File tree

1 file changed

+135
-1
lines changed

1 file changed

+135
-1
lines changed

drivers/cpuidle/cpuidle-pseries.c

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <asm/runlatch.h>
2222
#include <asm/idle.h>
2323
#include <asm/plpar_wrappers.h>
24+
#include <asm/rtas.h>
2425

2526
static struct cpuidle_driver pseries_idle_driver = {
2627
.name = "pseries_idle",
@@ -86,8 +87,131 @@ static void check_and_cede_processor(void)
8687
}
8788
}
8889

89-
#define NR_DEDICATED_STATES 2 /* snooze, CEDE */
90+
/*
91+
* XCEDE: Extended CEDE states discovered through the
92+
* "ibm,get-systems-parameter" RTAS call with the token
93+
* CEDE_LATENCY_TOKEN
94+
*/
95+
96+
/*
97+
* Section 7.3.16 System Parameters Option of PAPR version 2.8.1 has a
98+
* table with all the parameters to ibm,get-system-parameters.
99+
* CEDE_LATENCY_TOKEN corresponds to the token value for Cede Latency
100+
* Settings Information.
101+
*/
102+
#define CEDE_LATENCY_TOKEN 45
103+
104+
/*
105+
* If the platform supports the cede latency settings information system
106+
* parameter it must provide the following information in the NULL terminated
107+
* parameter string:
108+
*
109+
* a. The first byte is the length “N” of each cede latency setting record minus
110+
* one (zero indicates a length of 1 byte).
111+
*
112+
* b. For each supported cede latency setting a cede latency setting record
113+
* consisting of the first “N” bytes as per the following table.
114+
*
115+
* -----------------------------
116+
* | Field | Field |
117+
* | Name | Length |
118+
* -----------------------------
119+
* | Cede Latency | 1 Byte |
120+
* | Specifier Value | |
121+
* -----------------------------
122+
* | Maximum wakeup | |
123+
* | latency in | 8 Bytes |
124+
* | tb-ticks | |
125+
* -----------------------------
126+
* | Responsive to | |
127+
* | external | 1 Byte |
128+
* | interrupts | |
129+
* -----------------------------
130+
*
131+
* This version has cede latency record size = 10.
132+
*
133+
* The structure xcede_latency_payload represents a) and b) with
134+
* xcede_latency_record representing the table in b).
135+
*
136+
* xcede_latency_parameter is what gets returned by
137+
* ibm,get-systems-parameter RTAS call when made with
138+
* CEDE_LATENCY_TOKEN.
139+
*
140+
* These structures are only used to represent the data obtained by the RTAS
141+
* call. The data is in big-endian.
142+
*/
143+
struct xcede_latency_record {
144+
u8 hint;
145+
__be64 latency_ticks;
146+
u8 wake_on_irqs;
147+
} __packed;
148+
149+
// Make space for 16 records, which "should be enough".
150+
struct xcede_latency_payload {
151+
u8 record_size;
152+
struct xcede_latency_record records[16];
153+
} __packed;
154+
155+
struct xcede_latency_parameter {
156+
__be16 payload_size;
157+
struct xcede_latency_payload payload;
158+
u8 null_char;
159+
} __packed;
160+
161+
static unsigned int nr_xcede_records;
162+
static struct xcede_latency_parameter xcede_latency_parameter __initdata;
163+
164+
static int __init parse_cede_parameters(void)
165+
{
166+
struct xcede_latency_payload *payload;
167+
u32 total_xcede_records_size;
168+
u8 xcede_record_size;
169+
u16 payload_size;
170+
int ret, i;
171+
172+
ret = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
173+
NULL, CEDE_LATENCY_TOKEN, __pa(&xcede_latency_parameter),
174+
sizeof(xcede_latency_parameter));
175+
if (ret) {
176+
pr_err("xcede: Error parsing CEDE_LATENCY_TOKEN\n");
177+
return ret;
178+
}
179+
180+
payload_size = be16_to_cpu(xcede_latency_parameter.payload_size);
181+
payload = &xcede_latency_parameter.payload;
90182

183+
xcede_record_size = payload->record_size + 1;
184+
185+
if (xcede_record_size != sizeof(struct xcede_latency_record)) {
186+
pr_err("xcede: Expected record-size %lu. Observed size %u.\n",
187+
sizeof(struct xcede_latency_record), xcede_record_size);
188+
return -EINVAL;
189+
}
190+
191+
pr_info("xcede: xcede_record_size = %d\n", xcede_record_size);
192+
193+
/*
194+
* Since the payload_size includes the last NULL byte and the
195+
* xcede_record_size, the remaining bytes correspond to array of all
196+
* cede_latency settings.
197+
*/
198+
total_xcede_records_size = payload_size - 2;
199+
nr_xcede_records = total_xcede_records_size / xcede_record_size;
200+
201+
for (i = 0; i < nr_xcede_records; i++) {
202+
struct xcede_latency_record *record = &payload->records[i];
203+
u64 latency_ticks = be64_to_cpu(record->latency_ticks);
204+
u8 wake_on_irqs = record->wake_on_irqs;
205+
u8 hint = record->hint;
206+
207+
pr_info("xcede: Record %d : hint = %u, latency = 0x%llx tb ticks, Wake-on-irq = %u\n",
208+
i, hint, latency_ticks, wake_on_irqs);
209+
}
210+
211+
return 0;
212+
}
213+
214+
#define NR_DEDICATED_STATES 2 /* snooze, CEDE */
91215
static u8 cede_latency_hint[NR_DEDICATED_STATES];
92216

93217
static int dedicated_cede_loop(struct cpuidle_device *dev,
@@ -219,6 +343,15 @@ static int pseries_cpuidle_driver_init(void)
219343
return 0;
220344
}
221345

346+
static void __init parse_xcede_idle_states(void)
347+
{
348+
if (parse_cede_parameters())
349+
return;
350+
351+
pr_info("cpuidle : Skipping the %d Extended CEDE idle states\n",
352+
nr_xcede_records);
353+
}
354+
222355
/*
223356
* pseries_idle_probe()
224357
* Choose state table for shared versus dedicated partition
@@ -240,6 +373,7 @@ static int pseries_idle_probe(void)
240373
cpuidle_state_table = shared_states;
241374
max_idle_state = ARRAY_SIZE(shared_states);
242375
} else {
376+
parse_xcede_idle_states();
243377
cpuidle_state_table = dedicated_states;
244378
max_idle_state = NR_DEDICATED_STATES;
245379
}

0 commit comments

Comments
 (0)