Skip to content

Commit f46117b

Browse files
committed
Merge back earlier Intel thermal control material for 6.5.
2 parents 0bb619f + ea197ea commit f46117b

File tree

2 files changed

+275
-0
lines changed

2 files changed

+275
-0
lines changed

drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,151 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
203203
}
204204
EXPORT_SYMBOL(acpi_parse_art);
205205

206+
/*
207+
* acpi_parse_psvt - Passive Table (PSVT) for passive cooling
208+
*
209+
* @handle: ACPI handle of the device which contains PSVT
210+
* @psvt_count: the number of valid entries resulted from parsing PSVT
211+
* @psvtp: pointer to array of psvt entries
212+
*
213+
*/
214+
static int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **psvtp)
215+
{
216+
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
217+
int nr_bad_entries = 0, revision = 0;
218+
union acpi_object *p;
219+
acpi_status status;
220+
int i, result = 0;
221+
struct psvt *psvts;
222+
223+
if (!acpi_has_method(handle, "PSVT"))
224+
return -ENODEV;
225+
226+
status = acpi_evaluate_object(handle, "PSVT", NULL, &buffer);
227+
if (ACPI_FAILURE(status))
228+
return -ENODEV;
229+
230+
p = buffer.pointer;
231+
if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
232+
result = -EFAULT;
233+
goto end;
234+
}
235+
236+
/* first package is the revision number */
237+
if (p->package.count > 0) {
238+
union acpi_object *prev = &(p->package.elements[0]);
239+
240+
if (prev->type == ACPI_TYPE_INTEGER)
241+
revision = (int)prev->integer.value;
242+
} else {
243+
result = -EFAULT;
244+
goto end;
245+
}
246+
247+
/* Support only version 2 */
248+
if (revision != 2) {
249+
result = -EFAULT;
250+
goto end;
251+
}
252+
253+
*psvt_count = p->package.count - 1;
254+
if (!*psvt_count) {
255+
result = -EFAULT;
256+
goto end;
257+
}
258+
259+
psvts = kcalloc(*psvt_count, sizeof(*psvts), GFP_KERNEL);
260+
if (!psvts) {
261+
result = -ENOMEM;
262+
goto end;
263+
}
264+
265+
/* Start index is 1 because the first package is the revision number */
266+
for (i = 1; i < p->package.count; i++) {
267+
struct acpi_buffer psvt_int_format = { sizeof("RRNNNNNNNNNN"), "RRNNNNNNNNNN" };
268+
struct acpi_buffer psvt_str_format = { sizeof("RRNNNNNSNNNN"), "RRNNNNNSNNNN" };
269+
union acpi_object *package = &(p->package.elements[i]);
270+
struct psvt *psvt = &psvts[i - 1 - nr_bad_entries];
271+
struct acpi_buffer *psvt_format = &psvt_int_format;
272+
struct acpi_buffer element = { 0, NULL };
273+
union acpi_object *knob;
274+
struct acpi_device *res;
275+
struct psvt *psvt_ptr;
276+
277+
element.length = ACPI_ALLOCATE_BUFFER;
278+
element.pointer = NULL;
279+
280+
if (package->package.count >= ACPI_NR_PSVT_ELEMENTS) {
281+
knob = &(package->package.elements[ACPI_PSVT_CONTROL_KNOB]);
282+
} else {
283+
nr_bad_entries++;
284+
pr_info("PSVT package %d is invalid, ignored\n", i);
285+
continue;
286+
}
287+
288+
if (knob->type == ACPI_TYPE_STRING) {
289+
psvt_format = &psvt_str_format;
290+
if (knob->string.length > ACPI_LIMIT_STR_MAX_LEN - 1) {
291+
pr_info("PSVT package %d limit string len exceeds max\n", i);
292+
knob->string.length = ACPI_LIMIT_STR_MAX_LEN - 1;
293+
}
294+
}
295+
296+
status = acpi_extract_package(&(p->package.elements[i]), psvt_format, &element);
297+
if (ACPI_FAILURE(status)) {
298+
nr_bad_entries++;
299+
pr_info("PSVT package %d is invalid, ignored\n", i);
300+
continue;
301+
}
302+
303+
psvt_ptr = (struct psvt *)element.pointer;
304+
305+
memcpy(psvt, psvt_ptr, sizeof(*psvt));
306+
307+
/* The limit element can be string or U64 */
308+
psvt->control_knob_type = (u64)knob->type;
309+
310+
if (knob->type == ACPI_TYPE_STRING) {
311+
memset(&psvt->limit, 0, sizeof(u64));
312+
strncpy(psvt->limit.string, psvt_ptr->limit.str_ptr, knob->string.length);
313+
} else {
314+
psvt->limit.integer = psvt_ptr->limit.integer;
315+
}
316+
317+
kfree(element.pointer);
318+
319+
res = acpi_fetch_acpi_dev(psvt->source);
320+
if (!res) {
321+
nr_bad_entries++;
322+
pr_info("Failed to get source ACPI device\n");
323+
continue;
324+
}
325+
326+
res = acpi_fetch_acpi_dev(psvt->target);
327+
if (!res) {
328+
nr_bad_entries++;
329+
pr_info("Failed to get target ACPI device\n");
330+
continue;
331+
}
332+
}
333+
334+
/* don't count bad entries */
335+
*psvt_count -= nr_bad_entries;
336+
337+
if (!*psvt_count) {
338+
result = -EFAULT;
339+
kfree(psvts);
340+
goto end;
341+
}
342+
343+
*psvtp = psvts;
344+
345+
return 0;
346+
347+
end:
348+
kfree(buffer.pointer);
349+
return result;
350+
}
206351

207352
/* get device name from acpi handle */
208353
static void get_single_name(acpi_handle handle, char *name)
@@ -289,6 +434,57 @@ static int fill_trt(char __user *ubuf)
289434
return ret;
290435
}
291436

437+
static int fill_psvt(char __user *ubuf)
438+
{
439+
int i, ret, count, psvt_len;
440+
union psvt_object *psvt_user;
441+
struct psvt *psvts;
442+
443+
ret = acpi_parse_psvt(acpi_thermal_rel_handle, &count, &psvts);
444+
if (ret)
445+
return ret;
446+
447+
psvt_len = count * sizeof(*psvt_user);
448+
449+
psvt_user = kzalloc(psvt_len, GFP_KERNEL);
450+
if (!psvt_user) {
451+
ret = -ENOMEM;
452+
goto free_psvt;
453+
}
454+
455+
/* now fill in user psvt data */
456+
for (i = 0; i < count; i++) {
457+
/* userspace psvt needs device name instead of acpi reference */
458+
get_single_name(psvts[i].source, psvt_user[i].source_device);
459+
get_single_name(psvts[i].target, psvt_user[i].target_device);
460+
461+
psvt_user[i].priority = psvts[i].priority;
462+
psvt_user[i].sample_period = psvts[i].sample_period;
463+
psvt_user[i].passive_temp = psvts[i].passive_temp;
464+
psvt_user[i].source_domain = psvts[i].source_domain;
465+
psvt_user[i].control_knob = psvts[i].control_knob;
466+
psvt_user[i].step_size = psvts[i].step_size;
467+
psvt_user[i].limit_coeff = psvts[i].limit_coeff;
468+
psvt_user[i].unlimit_coeff = psvts[i].unlimit_coeff;
469+
psvt_user[i].control_knob_type = psvts[i].control_knob_type;
470+
if (psvt_user[i].control_knob_type == ACPI_TYPE_STRING)
471+
strncpy(psvt_user[i].limit.string, psvts[i].limit.string,
472+
ACPI_LIMIT_STR_MAX_LEN);
473+
else
474+
psvt_user[i].limit.integer = psvts[i].limit.integer;
475+
476+
}
477+
478+
if (copy_to_user(ubuf, psvt_user, psvt_len))
479+
ret = -EFAULT;
480+
481+
kfree(psvt_user);
482+
483+
free_psvt:
484+
kfree(psvts);
485+
return ret;
486+
}
487+
292488
static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
293489
unsigned long __arg)
294490
{
@@ -298,6 +494,7 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
298494
char __user *arg = (void __user *)__arg;
299495
struct trt *trts = NULL;
300496
struct art *arts = NULL;
497+
struct psvt *psvts;
301498

302499
switch (cmd) {
303500
case ACPI_THERMAL_GET_TRT_COUNT:
@@ -336,6 +533,27 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
336533
case ACPI_THERMAL_GET_ART:
337534
return fill_art(arg);
338535

536+
case ACPI_THERMAL_GET_PSVT_COUNT:
537+
ret = acpi_parse_psvt(acpi_thermal_rel_handle, &count, &psvts);
538+
if (!ret) {
539+
kfree(psvts);
540+
return put_user(count, (unsigned long __user *)__arg);
541+
}
542+
return ret;
543+
544+
case ACPI_THERMAL_GET_PSVT_LEN:
545+
/* total length of the data retrieved (count * PSVT entry size) */
546+
ret = acpi_parse_psvt(acpi_thermal_rel_handle, &count, &psvts);
547+
length = count * sizeof(union psvt_object);
548+
if (!ret) {
549+
kfree(psvts);
550+
return put_user(length, (unsigned long __user *)__arg);
551+
}
552+
return ret;
553+
554+
case ACPI_THERMAL_GET_PSVT:
555+
return fill_psvt(arg);
556+
339557
default:
340558
return -ENOTTY;
341559
}

drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@
1414
#define ACPI_THERMAL_GET_TRT _IOR(ACPI_THERMAL_MAGIC, 5, unsigned long)
1515
#define ACPI_THERMAL_GET_ART _IOR(ACPI_THERMAL_MAGIC, 6, unsigned long)
1616

17+
/*
18+
* ACPI_THERMAL_GET_PSVT_COUNT = Number of PSVT entries
19+
* ACPI_THERMAL_GET_PSVT_LEN = Total return data size (PSVT count x each
20+
* PSVT entry size)
21+
* ACPI_THERMAL_GET_PSVT = Get the data as an array of psvt_objects
22+
*/
23+
#define ACPI_THERMAL_GET_PSVT_LEN _IOR(ACPI_THERMAL_MAGIC, 7, unsigned long)
24+
#define ACPI_THERMAL_GET_PSVT_COUNT _IOR(ACPI_THERMAL_MAGIC, 8, unsigned long)
25+
#define ACPI_THERMAL_GET_PSVT _IOR(ACPI_THERMAL_MAGIC, 9, unsigned long)
26+
1727
struct art {
1828
acpi_handle source;
1929
acpi_handle target;
@@ -43,6 +53,32 @@ struct trt {
4353
u64 reserved4;
4454
} __packed;
4555

56+
#define ACPI_NR_PSVT_ELEMENTS 12
57+
#define ACPI_PSVT_CONTROL_KNOB 7
58+
#define ACPI_LIMIT_STR_MAX_LEN 8
59+
60+
struct psvt {
61+
acpi_handle source;
62+
acpi_handle target;
63+
u64 priority;
64+
u64 sample_period;
65+
u64 passive_temp;
66+
u64 source_domain;
67+
u64 control_knob;
68+
union {
69+
/* For limit_type = ACPI_TYPE_INTEGER */
70+
u64 integer;
71+
/* For limit_type = ACPI_TYPE_STRING */
72+
char string[ACPI_LIMIT_STR_MAX_LEN];
73+
char *str_ptr;
74+
} limit;
75+
u64 step_size;
76+
u64 limit_coeff;
77+
u64 unlimit_coeff;
78+
/* Spec calls this field reserved, so we borrow it for type info */
79+
u64 control_knob_type; /* ACPI_TYPE_STRING or ACPI_TYPE_INTEGER */
80+
} __packed;
81+
4682
#define ACPI_NR_ART_ELEMENTS 13
4783
/* for usrspace */
4884
union art_object {
@@ -77,6 +113,27 @@ union trt_object {
77113
u64 __data[8];
78114
};
79115

116+
union psvt_object {
117+
struct {
118+
char source_device[8];
119+
char target_device[8];
120+
u64 priority;
121+
u64 sample_period;
122+
u64 passive_temp;
123+
u64 source_domain;
124+
u64 control_knob;
125+
union {
126+
u64 integer;
127+
char string[ACPI_LIMIT_STR_MAX_LEN];
128+
} limit;
129+
u64 step_size;
130+
u64 limit_coeff;
131+
u64 unlimit_coeff;
132+
u64 control_knob_type;
133+
};
134+
u64 __data[ACPI_NR_PSVT_ELEMENTS];
135+
};
136+
80137
#ifdef __KERNEL__
81138
int acpi_thermal_rel_misc_device_add(acpi_handle handle);
82139
int acpi_thermal_rel_misc_device_remove(acpi_handle handle);

0 commit comments

Comments
 (0)