xref: /linux/drivers/platform/x86/lenovo/wmi-other.c (revision 4c2cd91bff6371b58e672e8791c3bfa70c1b821f)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Lenovo Other Mode WMI interface driver.
4  *
5  * This driver uses the fw_attributes class to expose the various WMI functions
6  * provided by the "Other Mode" WMI interface. This enables CPU and GPU power
7  * limit as well as various other attributes for devices that fall under the
8  * "Gaming Series" of Lenovo laptop devices. Each attribute exposed by the
9  * "Other Mode" interface has a corresponding Capability Data struct that
10  * allows the driver to probe details about the attribute such as if it is
11  * supported by the hardware, the default_value, max_value, min_value, and step
12  * increment.
13  *
14  * These attributes typically don't fit anywhere else in the sysfs and are set
15  * in Windows using one of Lenovo's multiple user applications.
16  *
17  * Additionally, this driver also exports tunable fan speed RPM to HWMON.
18  * Min/max RPM are also provided for reference.
19  *
20  * Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com>
21  *   - fw_attributes
22  *   - binding to Capability Data 01
23  *
24  * Copyright (C) 2025 Rong Zhang <i@rong.moe>
25  *   - HWMON
26  *   - binding to Capability Data 00 and Fan
27  */
28 
29 #include <linux/acpi.h>
30 #include <linux/bitfield.h>
31 #include <linux/cleanup.h>
32 #include <linux/component.h>
33 #include <linux/container_of.h>
34 #include <linux/device.h>
35 #include <linux/export.h>
36 #include <linux/gfp_types.h>
37 #include <linux/hwmon.h>
38 #include <linux/idr.h>
39 #include <linux/kdev_t.h>
40 #include <linux/kobject.h>
41 #include <linux/limits.h>
42 #include <linux/module.h>
43 #include <linux/platform_profile.h>
44 #include <linux/types.h>
45 #include <linux/wmi.h>
46 
47 #include "wmi-capdata.h"
48 #include "wmi-events.h"
49 #include "wmi-helpers.h"
50 #include "../firmware_attributes_class.h"
51 
52 #define LENOVO_OTHER_MODE_GUID "DC2A8805-3A8C-41BA-A6F7-092E0089CD3B"
53 
54 #define LWMI_DEVICE_ID_CPU 0x01
55 
56 #define LWMI_FEATURE_ID_CPU_SPPT 0x01
57 #define LWMI_FEATURE_ID_CPU_SPL 0x02
58 #define LWMI_FEATURE_ID_CPU_FPPT 0x03
59 
60 #define LWMI_FEATURE_ID_FAN_RPM 0x03
61 
62 #define LWMI_FEATURE_VALUE_GET 17
63 #define LWMI_FEATURE_VALUE_SET 18
64 
65 #define LWMI_FAN_ID_BASE 1
66 #define LWMI_FAN_NR 4
67 #define LWMI_FAN_ID(x) ((x) + LWMI_FAN_ID_BASE)
68 
69 #define LWMI_FAN_DIV 100
70 
71 #define LWMI_ATTR_ID_FAN_RPM(x)                                   \
72 	lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_RPM, \
73 		     LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x))
74 
75 #define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"
76 #define LWMI_OM_HWMON_NAME "lenovo_wmi_other"
77 
78 static DEFINE_IDA(lwmi_om_ida);
79 
80 enum attribute_property {
81 	DEFAULT_VAL,
82 	MAX_VAL,
83 	MIN_VAL,
84 	STEP_VAL,
85 	SUPPORTED,
86 };
87 
88 struct lwmi_fan_info {
89 	u32 supported;
90 	u32 last_target;
91 	long min_rpm;
92 	long max_rpm;
93 };
94 
95 struct lwmi_om_priv {
96 	struct component_master_ops *ops;
97 
98 	/* only valid after capdata bind */
99 	struct cd_list *cd00_list;
100 	struct cd_list *cd01_list;
101 
102 	struct device *hwmon_dev;
103 	struct device *fw_attr_dev;
104 	struct kset *fw_attr_kset;
105 	struct wmi_device *wdev;
106 	int ida_id;
107 
108 	struct lwmi_fan_info fan_info[LWMI_FAN_NR];
109 
110 	struct {
111 		bool capdata00_collected : 1;
112 		bool capdata_fan_collected : 1;
113 	} fan_flags;
114 };
115 
116 /*
117  * Visibility of fan channels:
118  *
119  * +-------------------+---------+------------------+-----------------------+------------+
120  * |                   | default | +expose_all_fans | +relax_fan_constraint | +both      |
121  * +-------------------+---------+------------------+-----------------------+------------+
122  * | canonical         | RW      | RW               | RW+relaxed            | RW+relaxed |
123  * +-------------------+---------+------------------+-----------------------+------------+
124  * | -capdata_fan[idx] | N       | RO               | N                     | RW+relaxed |
125  * +-------------------+---------+------------------+-----------------------+------------+
126  *
127  * Note:
128  * 1. LWMI_ATTR_ID_FAN_RPM[idx].supported is always checked before exposing a channel.
129  * 2. -capdata_fan implies -capdata_fan[idx].
130  */
131 static bool expose_all_fans;
132 module_param(expose_all_fans, bool, 0444);
133 MODULE_PARM_DESC(expose_all_fans,
134 	"This option skips some capability checks and solely relies on per-channel ones "
135 	"to expose fan attributes. Use with caution.");
136 
137 static bool relax_fan_constraint;
138 module_param(relax_fan_constraint, bool, 0444);
139 MODULE_PARM_DESC(relax_fan_constraint,
140 	"Do not enforce fan RPM constraint (div/min/max) "
141 	"and enables fan tuning when such data is missing. "
142 	"Enabling this may results in HWMON attributes being out-of-sync, "
143 	"and setting a too low RPM stops the fan. Use with caution.");
144 
145 /* ======== HWMON (component: lenovo-wmi-capdata 00 & fan) ======== */
146 
147 /**
148  * lwmi_om_fan_get_set() - Get or set fan RPM value of specified fan
149  * @priv: Driver private data structure
150  * @channel: Fan channel index (0-based)
151  * @val: Pointer to value (input for set, output for get)
152  * @set: True to set value, false to get value
153  *
154  * Communicates with WMI interface to either retrieve current fan RPM
155  * or set target fan RPM.
156  *
157  * Return: 0 on success, or an error code.
158  */
lwmi_om_fan_get_set(struct lwmi_om_priv * priv,int channel,u32 * val,bool set)159 static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set)
160 {
161 	struct wmi_method_args_32 args = {};
162 	u32 method_id, retval;
163 	int err;
164 
165 	method_id = set ? LWMI_FEATURE_VALUE_SET : LWMI_FEATURE_VALUE_GET;
166 	args.arg0 = LWMI_ATTR_ID_FAN_RPM(channel);
167 	args.arg1 = set ? *val : 0;
168 
169 	err = lwmi_dev_evaluate_int(priv->wdev, 0x0, method_id,
170 				    (unsigned char *)&args, sizeof(args), &retval);
171 	if (err)
172 		return err;
173 
174 	if (!set) {
175 		*val = retval;
176 		return 0;
177 	}
178 
179 	/*
180 	 * It seems that 0 means "no error" and 1 means "done". Apparently
181 	 * different firmware teams have different thoughts on indicating
182 	 * success, so we accepts both.
183 	 */
184 	return (retval == 0 || retval == 1) ? 0 : -EIO;
185 }
186 
187 /**
188  * lwmi_om_hwmon_is_visible() - Determine visibility of HWMON attributes
189  * @drvdata: Driver private data
190  * @type: Sensor type
191  * @attr: Attribute identifier
192  * @channel: Channel index
193  *
194  * Determines whether an HWMON attribute should be visible in sysfs
195  * based on hardware capabilities and current configuration.
196  *
197  * Return: permission mode, or 0 if invisible.
198  */
lwmi_om_hwmon_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)199 static umode_t lwmi_om_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
200 					u32 attr, int channel)
201 {
202 	struct lwmi_om_priv *priv = (struct lwmi_om_priv *)drvdata;
203 	bool visible = false;
204 
205 	if (type == hwmon_fan) {
206 		if (!(priv->fan_info[channel].supported & LWMI_SUPP_VALID))
207 			return 0;
208 
209 		switch (attr) {
210 		case hwmon_fan_target:
211 			if (!(priv->fan_info[channel].supported & LWMI_SUPP_SET))
212 				return 0;
213 
214 			if (relax_fan_constraint ||
215 			    (priv->fan_info[channel].min_rpm >= 0 &&
216 			     priv->fan_info[channel].max_rpm >= 0))
217 				return 0644;
218 
219 			/*
220 			 * Reaching here implies expose_all_fans is set.
221 			 * See lwmi_om_hwmon_add().
222 			 */
223 			dev_warn_once(&priv->wdev->dev,
224 				      "fan tuning disabled due to missing RPM constraint\n");
225 			return 0;
226 		case hwmon_fan_div:
227 		case hwmon_fan_input:
228 			visible = priv->fan_info[channel].supported & LWMI_SUPP_GET;
229 			break;
230 		case hwmon_fan_min:
231 			visible = priv->fan_info[channel].min_rpm >= 0;
232 			break;
233 		case hwmon_fan_max:
234 			visible = priv->fan_info[channel].max_rpm >= 0;
235 			break;
236 		}
237 	}
238 
239 	return visible ? 0444 : 0;
240 }
241 
242 /**
243  * lwmi_om_hwmon_read() - Read HWMON sensor data
244  * @dev: Device pointer
245  * @type: Sensor type
246  * @attr: Attribute identifier
247  * @channel: Channel index
248  * @val: Pointer to store value
249  *
250  * Reads current sensor values from hardware through WMI interface.
251  *
252  * Return: 0 on success, or an error code.
253  */
lwmi_om_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)254 static int lwmi_om_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
255 			      u32 attr, int channel, long *val)
256 {
257 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
258 	u32 retval = 0;
259 	int err;
260 
261 	if (type == hwmon_fan) {
262 		switch (attr) {
263 		/*
264 		 * The EC has an internal RPM divisor (i.e., the raw register value is
265 		 * RPM / fanY_div). For fanY_input, the WMI method reads the register
266 		 * value and returns raw * fanY_div. For fanY_target, the WMI method
267 		 * divides the written value by fanY_div before writing it to the EC.
268 		 *
269 		 * As a result, reading fanY_input always returns a multiple of fanY_div,
270 		 * while writing to fanY_target loses the remainder.
271 		 */
272 		case hwmon_fan_div:
273 			*val = LWMI_FAN_DIV;
274 			return 0;
275 		case hwmon_fan_input:
276 			err = lwmi_om_fan_get_set(priv, channel, &retval, false);
277 			if (err)
278 				return err;
279 
280 			*val = retval;
281 			return 0;
282 		case hwmon_fan_target:
283 			*val = priv->fan_info[channel].last_target;
284 			return 0;
285 		case hwmon_fan_min:
286 			*val = priv->fan_info[channel].min_rpm;
287 			return 0;
288 		case hwmon_fan_max:
289 			*val = priv->fan_info[channel].max_rpm;
290 			return 0;
291 		}
292 	}
293 
294 	return -EOPNOTSUPP;
295 }
296 
297 /**
298  * lwmi_om_hwmon_write() - Write HWMON sensor data
299  * @dev: Device pointer
300  * @type: Sensor type
301  * @attr: Attribute identifier
302  * @channel: Channel index
303  * @val: Value to write
304  *
305  * Writes configuration values to hardware through WMI interface.
306  *
307  * Return: 0 on success, or an error code.
308  */
lwmi_om_hwmon_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)309 static int lwmi_om_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
310 			       u32 attr, int channel, long val)
311 {
312 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
313 	u32 raw, min_rpm, max_rpm;
314 	int err;
315 
316 	if (type == hwmon_fan) {
317 		switch (attr) {
318 		case hwmon_fan_target:
319 			if (relax_fan_constraint) {
320 				min_rpm = 1;
321 				max_rpm = U16_MAX;
322 			} else {
323 				min_rpm = priv->fan_info[channel].min_rpm;
324 				max_rpm = priv->fan_info[channel].max_rpm;
325 			}
326 
327 			/* 0 means "auto". */
328 			if (val != 0 && (val < min_rpm || val > max_rpm))
329 				return -EINVAL;
330 
331 			/*
332 			 * The effective fanY_target is always a multiple of fanY_div
333 			 * due to the EC's internal RPM divisor (see lwmi_om_hwmon_read).
334 			 *
335 			 * Round down the written value to the nearest multiple of fanY_div
336 			 * to prevent mismatch between the effective value and last_target.
337 			 *
338 			 * For relax_fan_constraint, skip this conversion as setting a
339 			 * sub-fanY_div value is necessary to completely stop the fan on
340 			 * some devices.
341 			 */
342 			if (!relax_fan_constraint)
343 				raw = val / LWMI_FAN_DIV * LWMI_FAN_DIV;
344 			else
345 				raw = val;
346 
347 			err = lwmi_om_fan_get_set(priv, channel, &raw, true);
348 			if (err)
349 				return err;
350 
351 			priv->fan_info[channel].last_target = raw;
352 			return 0;
353 		}
354 	}
355 
356 	return -EOPNOTSUPP;
357 }
358 
359 static const struct hwmon_channel_info * const lwmi_om_hwmon_info[] = {
360 	/* Must match LWMI_FAN_NR. */
361 	HWMON_CHANNEL_INFO(fan,
362 			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
363 			   HWMON_F_MIN | HWMON_F_MAX,
364 			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
365 			   HWMON_F_MIN | HWMON_F_MAX,
366 			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
367 			   HWMON_F_MIN | HWMON_F_MAX,
368 			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
369 			   HWMON_F_MIN | HWMON_F_MAX),
370 	NULL
371 };
372 
373 static const struct hwmon_ops lwmi_om_hwmon_ops = {
374 	.is_visible = lwmi_om_hwmon_is_visible,
375 	.read = lwmi_om_hwmon_read,
376 	.write = lwmi_om_hwmon_write,
377 };
378 
379 static const struct hwmon_chip_info lwmi_om_hwmon_chip_info = {
380 	.ops = &lwmi_om_hwmon_ops,
381 	.info = lwmi_om_hwmon_info,
382 };
383 
384 /**
385  * lwmi_om_hwmon_add() - Register HWMON device if all info is collected
386  * @priv: Driver private data
387  */
lwmi_om_hwmon_add(struct lwmi_om_priv * priv)388 static void lwmi_om_hwmon_add(struct lwmi_om_priv *priv)
389 {
390 	int i, valid;
391 
392 	if (WARN_ON(priv->hwmon_dev))
393 		return;
394 
395 	if (!priv->fan_flags.capdata00_collected || !priv->fan_flags.capdata_fan_collected) {
396 		dev_dbg(&priv->wdev->dev, "HWMON registration pending (00: %d, fan: %d)\n",
397 			priv->fan_flags.capdata00_collected,
398 			priv->fan_flags.capdata_fan_collected);
399 		return;
400 	}
401 
402 	if (expose_all_fans)
403 		dev_warn(&priv->wdev->dev, "all fans exposed. Use with caution\n");
404 
405 	if (relax_fan_constraint)
406 		dev_warn(&priv->wdev->dev, "fan RPM constraint relaxed. Use with caution\n");
407 
408 	valid = 0;
409 	for (i = 0; i < LWMI_FAN_NR; i++) {
410 		if (!(priv->fan_info[i].supported & LWMI_SUPP_VALID))
411 			continue;
412 
413 		valid++;
414 
415 		if (!expose_all_fans &&
416 		    (priv->fan_info[i].min_rpm < 0 || priv->fan_info[i].max_rpm < 0)) {
417 			dev_dbg(&priv->wdev->dev, "missing RPM constraint for fan%d, hiding\n",
418 				LWMI_FAN_ID(i));
419 			priv->fan_info[i].supported = 0;
420 			valid--;
421 		}
422 	}
423 
424 	if (valid == 0) {
425 		dev_warn(&priv->wdev->dev,
426 			 "fan reporting/tuning is unsupported on this device\n");
427 		return;
428 	}
429 
430 	priv->hwmon_dev = hwmon_device_register_with_info(&priv->wdev->dev,
431 							  LWMI_OM_HWMON_NAME, priv,
432 							  &lwmi_om_hwmon_chip_info,
433 							  NULL);
434 	if (IS_ERR(priv->hwmon_dev)) {
435 		dev_warn(&priv->wdev->dev, "failed to register HWMON device: %ld\n",
436 			 PTR_ERR(priv->hwmon_dev));
437 		priv->hwmon_dev = NULL;
438 		return;
439 	}
440 
441 	dev_dbg(&priv->wdev->dev, "registered HWMON device\n");
442 }
443 
444 /**
445  * lwmi_om_hwmon_remove() - Unregister HWMON device
446  * @priv: Driver private data
447  *
448  * Unregisters the HWMON device if applicable.
449  */
lwmi_om_hwmon_remove(struct lwmi_om_priv * priv)450 static void lwmi_om_hwmon_remove(struct lwmi_om_priv *priv)
451 {
452 	if (!priv->hwmon_dev)
453 		return;
454 
455 	hwmon_device_unregister(priv->hwmon_dev);
456 	priv->hwmon_dev = NULL;
457 }
458 
459 /**
460  * lwmi_om_fan_info_init() - Initialzie fan info
461  * @priv: Driver private data
462  *
463  * lwmi_om_fan_info_collect_cd00() and lwmi_om_fan_info_collect_cd_fan() may be
464  * called in an arbitrary order. Hence, initializion must be done before.
465  */
lwmi_om_fan_info_init(struct lwmi_om_priv * priv)466 static void lwmi_om_fan_info_init(struct lwmi_om_priv *priv)
467 {
468 	int i;
469 
470 	for (i = 0; i < LWMI_FAN_NR; i++) {
471 		priv->fan_info[i] = (struct lwmi_fan_info) {
472 			.supported = 0,
473 			/*
474 			 * Assume 0 on probe as the EC resets all fans to auto mode on (re)boot.
475 			 *
476 			 * Note that S0ix (s2idle) preserves the RPM target, so we don't need
477 			 * suspend/resume callbacks. This behavior has not been tested on S3-
478 			 * capable devices, but I doubt if such devices even have this interface.
479 			 */
480 			.last_target = 0,
481 			.min_rpm = -ENODATA,
482 			.max_rpm = -ENODATA,
483 		};
484 	}
485 
486 	priv->fan_flags.capdata00_collected = false;
487 	priv->fan_flags.capdata_fan_collected = false;
488 }
489 
490 /**
491  * lwmi_om_fan_info_collect_cd00() - Collect fan info from capdata 00
492  * @priv: Driver private data
493  */
lwmi_om_fan_info_collect_cd00(struct lwmi_om_priv * priv)494 static void lwmi_om_fan_info_collect_cd00(struct lwmi_om_priv *priv)
495 {
496 	struct capdata00 capdata00;
497 	int i, err;
498 
499 	dev_dbg(&priv->wdev->dev, "Collecting fan info from capdata00\n");
500 
501 	for (i = 0; i < LWMI_FAN_NR; i++) {
502 		err = lwmi_cd00_get_data(priv->cd00_list, LWMI_ATTR_ID_FAN_RPM(i), &capdata00);
503 		priv->fan_info[i].supported = err ? 0 : capdata00.supported;
504 	}
505 
506 	priv->fan_flags.capdata00_collected = true;
507 	lwmi_om_hwmon_add(priv);
508 }
509 
510 /**
511  * lwmi_om_fan_info_collect_cd_fan() - Collect fan info from capdata fan
512  * @dev: Pointer to the lenovo-wmi-other device
513  * @cd_fan_list: Pointer to the capdata fan list
514  */
lwmi_om_fan_info_collect_cd_fan(struct device * dev,struct cd_list * cd_fan_list)515 static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list *cd_fan_list)
516 {
517 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
518 	struct capdata_fan capdata_fan;
519 	int i, err;
520 
521 	dev_dbg(dev, "Collecting fan info from capdata_fan\n");
522 
523 	if (!cd_fan_list)
524 		goto out;
525 
526 	for (i = 0; i < LWMI_FAN_NR; i++) {
527 		err = lwmi_cd_fan_get_data(cd_fan_list, LWMI_FAN_ID(i), &capdata_fan);
528 		if (err)
529 			continue;
530 
531 		priv->fan_info[i].min_rpm = capdata_fan.min_rpm;
532 		priv->fan_info[i].max_rpm = capdata_fan.max_rpm;
533 	}
534 
535 out:
536 	priv->fan_flags.capdata_fan_collected = true;
537 	lwmi_om_hwmon_add(priv);
538 }
539 
540 /* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */
541 
542 struct tunable_attr_01 {
543 	struct device *dev;
544 	u8 feature_id;
545 	u8 device_id;
546 	u8 type_id;
547 	u8 cd_mode_id; /* mode arg for searching capdata */
548 	u8 cv_mode_id; /* mode arg for set/get current_value */
549 };
550 
551 /**
552  * tunable_attr_01_id() - Formats a tunable_attr_01 to a capdata attribute ID
553  * @attr: The tunable_attr_01 to format.
554  * @mode: The u8 corresponding to the wmi-gamezone mode for set/get.
555  *
556  * Return: encoded capability data attribute ID.
557  */
tunable_attr_01_id(struct tunable_attr_01 * attr,u8 mode)558 static u32 tunable_attr_01_id(struct tunable_attr_01 *attr, u8 mode)
559 {
560 	return lwmi_attr_id(attr->device_id, attr->feature_id, mode, attr->type_id);
561 }
562 
563 static struct tunable_attr_01 ppt_pl1_spl = {
564 	.device_id = LWMI_DEVICE_ID_CPU,
565 	.feature_id = LWMI_FEATURE_ID_CPU_SPL,
566 	.type_id = LWMI_TYPE_ID_NONE,
567 };
568 
569 static struct tunable_attr_01 ppt_pl2_sppt = {
570 	.device_id = LWMI_DEVICE_ID_CPU,
571 	.feature_id = LWMI_FEATURE_ID_CPU_SPPT,
572 	.type_id = LWMI_TYPE_ID_NONE,
573 };
574 
575 static struct tunable_attr_01 ppt_pl3_fppt = {
576 	.device_id = LWMI_DEVICE_ID_CPU,
577 	.feature_id = LWMI_FEATURE_ID_CPU_FPPT,
578 	.type_id = LWMI_TYPE_ID_NONE,
579 };
580 
581 struct capdata01_attr_group {
582 	const struct attribute_group *attr_group;
583 	struct tunable_attr_01 *tunable_attr;
584 };
585 
586 /* Attribute Methods */
587 
588 /**
589  * int_type_show() - Emit the data type for an integer attribute
590  * @kobj: Pointer to the driver object.
591  * @kattr: Pointer to the attribute calling this function.
592  * @buf: The buffer to write to.
593  *
594  * Return: Number of characters written to buf.
595  */
int_type_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf)596 static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *kattr,
597 			     char *buf)
598 {
599 	return sysfs_emit(buf, "integer\n");
600 }
601 
602 /**
603  * attr_capdata01_show() - Get the value of the specified attribute property
604  *
605  * @kobj: Pointer to the driver object.
606  * @kattr: Pointer to the attribute calling this function.
607  * @buf: The buffer to write to.
608  * @tunable_attr: The attribute to be read.
609  * @prop: The property of this attribute to be read.
610  *
611  * Retrieves the given property from the capability data 01 struct for the
612  * specified attribute's "custom" thermal mode. This function is intended
613  * to be generic so it can be called from any integer attributes "_show"
614  * function.
615  *
616  * If the WMI is success the sysfs attribute is notified.
617  *
618  * Return: Either number of characters written to buf, or an error code.
619  */
attr_capdata01_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf,struct tunable_attr_01 * tunable_attr,enum attribute_property prop)620 static ssize_t attr_capdata01_show(struct kobject *kobj,
621 				   struct kobj_attribute *kattr, char *buf,
622 				   struct tunable_attr_01 *tunable_attr,
623 				   enum attribute_property prop)
624 {
625 	struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
626 	struct capdata01 capdata;
627 	u32 attribute_id;
628 	int value, ret;
629 
630 	attribute_id = tunable_attr_01_id(tunable_attr, tunable_attr->cd_mode_id);
631 
632 	ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
633 	if (ret)
634 		return ret;
635 
636 	switch (prop) {
637 	case DEFAULT_VAL:
638 		value = capdata.default_value;
639 		break;
640 	case MAX_VAL:
641 		value = capdata.max_value;
642 		break;
643 	case MIN_VAL:
644 		value = capdata.min_value;
645 		break;
646 	case STEP_VAL:
647 		value = capdata.step;
648 		break;
649 	default:
650 		return -EINVAL;
651 	}
652 
653 	return sysfs_emit(buf, "%d\n", value);
654 }
655 
656 /**
657  * attr_current_value_store() - Set the current value of the given attribute
658  * @kobj: Pointer to the driver object.
659  * @kattr: Pointer to the attribute calling this function.
660  * @buf: The buffer to read from, this is parsed to `int` type.
661  * @count: Required by sysfs attribute macros, pass in from the callee attr.
662  * @tunable_attr: The attribute to be stored.
663  *
664  * Sets the value of the given attribute when operating under the "custom"
665  * smartfan profile. The current smartfan profile is retrieved from the
666  * lenovo-wmi-gamezone driver and error is returned if the result is not
667  * "custom". This function is intended to be generic so it can be called from
668  * any integer attribute's "_store" function. The integer to be sent to the WMI
669  * method is range checked and an error code is returned if out of range.
670  *
671  * If the value is valid and WMI is success, then the sysfs attribute is
672  * notified.
673  *
674  * Return: Either count, or an error code.
675  */
attr_current_value_store(struct kobject * kobj,struct kobj_attribute * kattr,const char * buf,size_t count,struct tunable_attr_01 * tunable_attr)676 static ssize_t attr_current_value_store(struct kobject *kobj,
677 					struct kobj_attribute *kattr,
678 					const char *buf, size_t count,
679 					struct tunable_attr_01 *tunable_attr)
680 {
681 	struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
682 	struct wmi_method_args_32 args = {};
683 	struct capdata01 capdata;
684 	enum thermal_mode mode;
685 	u32 value;
686 	int ret;
687 
688 	ret = lwmi_tm_notifier_call(&mode);
689 	if (ret)
690 		return ret;
691 
692 	if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM)
693 		return -EBUSY;
694 
695 	args.arg0 = tunable_attr_01_id(tunable_attr, tunable_attr->cd_mode_id);
696 
697 	ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata);
698 	if (ret)
699 		return ret;
700 
701 	ret = kstrtouint(buf, 10, &value);
702 	if (ret)
703 		return ret;
704 
705 	if (value < capdata.min_value || value > capdata.max_value)
706 		return -EINVAL;
707 
708 	args.arg0 = tunable_attr_01_id(tunable_attr, tunable_attr->cv_mode_id);
709 	args.arg1 = value;
710 
711 	ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,
712 				    (unsigned char *)&args, sizeof(args), NULL);
713 	if (ret)
714 		return ret;
715 
716 	return count;
717 };
718 
719 /**
720  * attr_current_value_show() - Get the current value of the given attribute
721  * @kobj: Pointer to the driver object.
722  * @kattr: Pointer to the attribute calling this function.
723  * @buf: The buffer to write to.
724  * @tunable_attr: The attribute to be read.
725  *
726  * Retrieves the value of the given attribute for the current smartfan profile.
727  * The current smartfan profile is retrieved from the lenovo-wmi-gamezone driver.
728  * This function is intended to be generic so it can be called from any integer
729  * attribute's "_show" function.
730  *
731  * If the WMI is success the sysfs attribute is notified.
732  *
733  * Return: Either number of characters written to buf, or an error code.
734  */
attr_current_value_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf,struct tunable_attr_01 * tunable_attr)735 static ssize_t attr_current_value_show(struct kobject *kobj,
736 				       struct kobj_attribute *kattr, char *buf,
737 				       struct tunable_attr_01 *tunable_attr)
738 {
739 	struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
740 	struct wmi_method_args_32 args = {};
741 	enum thermal_mode mode;
742 	int retval;
743 	int ret;
744 
745 	ret = lwmi_tm_notifier_call(&mode);
746 	if (ret)
747 		return ret;
748 
749 	/* If "no-mode" is the supported mode, ensure we never send current mode */
750 	if (tunable_attr->cv_mode_id == LWMI_GZ_THERMAL_MODE_NONE)
751 		mode = tunable_attr->cv_mode_id;
752 
753 	args.arg0 = tunable_attr_01_id(tunable_attr, mode);
754 
755 	ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
756 				    (unsigned char *)&args, sizeof(args),
757 				    &retval);
758 	if (ret)
759 		return ret;
760 
761 	return sysfs_emit(buf, "%d\n", retval);
762 }
763 
764 /**
765  * lwmi_attr_01_is_supported() - Determine if the given attribute is supported.
766  * @tunable_attr: The attribute to verify.
767  *
768  * For an attribute to be supported it must have a functional get/set method,
769  * as well as associated capability data stored in the capdata01 table.
770  *
771  * First check if the attribute has a corresponding data table under custom mode
772  * (0xff), then under no mode (0x00). If either of those passes, check if the
773  * supported field of the capdata struct is > 0. If it is supported, store the
774  * successful mode in the cd_mode_id field of tunable_attr.
775  *
776  * If the attribute capdata shows it is supported, attempt to determine the mode
777  * for the current value property get/set methods using a similar pattern to the
778  * capdata table check. If the value returned by either mode is 0 or an error,
779  * assume that mode is not supported. Otherwise, store the successful mode in the
780  * cv_mode_id field of tunable_attr.
781  *
782  * If any of the above checks fail then the attribute is not fully supported.
783  *
784  * Return: true if capdata and set/get modes are found, otherwise false.
785  */
lwmi_attr_01_is_supported(struct tunable_attr_01 * tunable_attr)786 static bool lwmi_attr_01_is_supported(struct tunable_attr_01 *tunable_attr)
787 {
788 	u8 modes[2] = { LWMI_GZ_THERMAL_MODE_CUSTOM, LWMI_GZ_THERMAL_MODE_NONE };
789 	struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
790 	struct wmi_method_args_32 args = {};
791 	bool cd_mode_found = false;
792 	bool cv_mode_found = false;
793 	struct capdata01 capdata;
794 	int retval, ret, i;
795 
796 	/* Determine tunable_attr->cd_mode_id */
797 	for (i = 0; i < ARRAY_SIZE(modes); i++) {
798 		args.arg0 = tunable_attr_01_id(tunable_attr, modes[i]);
799 
800 		ret = lwmi_cd01_get_data(priv->cd01_list, args.arg0, &capdata);
801 		if (ret || !capdata.supported)
802 			continue;
803 
804 		tunable_attr->cd_mode_id = modes[i];
805 		cd_mode_found = true;
806 		break;
807 	}
808 
809 	if (!cd_mode_found)
810 		return cd_mode_found;
811 
812 	dev_dbg(tunable_attr->dev,
813 		"cd_mode_id: %#010x\n", args.arg0);
814 
815 	/* Determine tunable_attr->cv_mode_id, returns 1 if supported */
816 	for (i = 0; i < ARRAY_SIZE(modes); i++) {
817 		args.arg0 = tunable_attr_01_id(tunable_attr, modes[i]);
818 
819 		ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
820 					    (u8 *)&args, sizeof(args),
821 					    &retval);
822 		if (ret || !retval)
823 			continue;
824 
825 		tunable_attr->cv_mode_id = modes[i];
826 		cv_mode_found = true;
827 		break;
828 	}
829 
830 	if (!cv_mode_found)
831 		return cv_mode_found;
832 
833 	dev_dbg(tunable_attr->dev, "cv_mode_id: %#010x, attribute support level: %#010x\n",
834 		args.arg0, capdata.supported);
835 
836 	return capdata.supported > 0;
837 }
838 
839 /* Lenovo WMI Other Mode Attribute macros */
840 #define __LWMI_ATTR_RO(_func, _name)                                  \
841 	{                                                             \
842 		.attr = { .name = __stringify(_name), .mode = 0444 }, \
843 		.show = _func##_##_name##_show,                       \
844 	}
845 
846 #define __LWMI_ATTR_RO_AS(_name, _show)                               \
847 	{                                                             \
848 		.attr = { .name = __stringify(_name), .mode = 0444 }, \
849 		.show = _show,                                        \
850 	}
851 
852 #define __LWMI_ATTR_RW(_func, _name) \
853 	__ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
854 
855 /* Shows a formatted static variable */
856 #define __LWMI_ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val)                     \
857 	static ssize_t _attrname##_##_prop##_show(                             \
858 		struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
859 	{                                                                      \
860 		return sysfs_emit(buf, _fmt, _val);                            \
861 	}                                                                      \
862 	static struct kobj_attribute attr_##_attrname##_##_prop =              \
863 		__LWMI_ATTR_RO(_attrname, _prop)
864 
865 /* Attribute current value read/write */
866 #define __LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname)                          \
867 	static ssize_t _attrname##_current_value_store(                        \
868 		struct kobject *kobj, struct kobj_attribute *kattr,            \
869 		const char *buf, size_t count)                                 \
870 	{                                                                      \
871 		return attr_current_value_store(kobj, kattr, buf, count,       \
872 						&_attrname);                   \
873 	}                                                                      \
874 	static ssize_t _attrname##_current_value_show(                         \
875 		struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
876 	{                                                                      \
877 		return attr_current_value_show(kobj, kattr, buf, &_attrname);  \
878 	}                                                                      \
879 	static struct kobj_attribute attr_##_attrname##_current_value =        \
880 		__LWMI_ATTR_RW(_attrname, current_value)
881 
882 /* Attribute property read only */
883 #define __LWMI_TUNABLE_RO_CAP01(_prop, _attrname, _prop_type)                  \
884 	static ssize_t _attrname##_##_prop##_show(                             \
885 		struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
886 	{                                                                      \
887 		return attr_capdata01_show(kobj, kattr, buf, &_attrname,       \
888 					   _prop_type);                        \
889 	}                                                                      \
890 	static struct kobj_attribute attr_##_attrname##_##_prop =              \
891 		__LWMI_ATTR_RO(_attrname, _prop)
892 
893 #define LWMI_ATTR_GROUP_TUNABLE_CAP01(_attrname, _fsname, _dispname)      \
894 	__LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname);                    \
895 	__LWMI_TUNABLE_RO_CAP01(default_value, _attrname, DEFAULT_VAL);   \
896 	__LWMI_ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
897 	__LWMI_TUNABLE_RO_CAP01(max_value, _attrname, MAX_VAL);           \
898 	__LWMI_TUNABLE_RO_CAP01(min_value, _attrname, MIN_VAL);           \
899 	__LWMI_TUNABLE_RO_CAP01(scalar_increment, _attrname, STEP_VAL);   \
900 	static struct kobj_attribute attr_##_attrname##_type =            \
901 		__LWMI_ATTR_RO_AS(type, int_type_show);                   \
902 	static struct attribute *_attrname##_attrs[] = {                  \
903 		&attr_##_attrname##_current_value.attr,                   \
904 		&attr_##_attrname##_default_value.attr,                   \
905 		&attr_##_attrname##_display_name.attr,                    \
906 		&attr_##_attrname##_max_value.attr,                       \
907 		&attr_##_attrname##_min_value.attr,                       \
908 		&attr_##_attrname##_scalar_increment.attr,                \
909 		&attr_##_attrname##_type.attr,                            \
910 		NULL,                                                     \
911 	};                                                                \
912 	static const struct attribute_group _attrname##_attr_group = {    \
913 		.name = _fsname, .attrs = _attrname##_attrs               \
914 	}
915 
916 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl, "ppt_pl1_spl",
917 			      "Set the CPU sustained power limit");
918 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt, "ppt_pl2_sppt",
919 			      "Set the CPU slow package power tracking limit");
920 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt, "ppt_pl3_fppt",
921 			      "Set the CPU fast package power tracking limit");
922 
923 static struct capdata01_attr_group cd01_attr_groups[] = {
924 	{ &ppt_pl1_spl_attr_group, &ppt_pl1_spl },
925 	{ &ppt_pl2_sppt_attr_group, &ppt_pl2_sppt },
926 	{ &ppt_pl3_fppt_attr_group, &ppt_pl3_fppt },
927 	{},
928 };
929 
930 /**
931  * lwmi_om_fw_attr_add() - Register all firmware_attributes_class members
932  * @priv: The Other Mode driver data.
933  */
lwmi_om_fw_attr_add(struct lwmi_om_priv * priv)934 static void lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
935 {
936 	unsigned int i;
937 	int err;
938 
939 	err = ida_alloc(&lwmi_om_ida, GFP_KERNEL);
940 	if (err < 0)
941 		goto err_no_ida;
942 
943 	priv->ida_id = err;
944 
945 	priv->fw_attr_dev = device_create(&firmware_attributes_class, NULL,
946 					  MKDEV(0, 0), NULL, "%s-%u",
947 					  LWMI_OM_FW_ATTR_BASE_PATH,
948 					  priv->ida_id);
949 	if (IS_ERR(priv->fw_attr_dev)) {
950 		err = PTR_ERR(priv->fw_attr_dev);
951 		goto err_free_ida;
952 	}
953 
954 	priv->fw_attr_kset = kset_create_and_add("attributes", NULL,
955 						 &priv->fw_attr_dev->kobj);
956 	if (!priv->fw_attr_kset) {
957 		err = -ENOMEM;
958 		goto err_destroy_classdev;
959 	}
960 
961 	for (i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++) {
962 		cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev;
963 		if (!lwmi_attr_01_is_supported(cd01_attr_groups[i].tunable_attr))
964 			continue;
965 
966 		err = sysfs_create_group(&priv->fw_attr_kset->kobj,
967 					 cd01_attr_groups[i].attr_group);
968 		if (err)
969 			goto err_remove_groups;
970 	}
971 	return;
972 
973 err_remove_groups:
974 	while (i--)
975 		sysfs_remove_group(&priv->fw_attr_kset->kobj,
976 				   cd01_attr_groups[i].attr_group);
977 
978 	kset_unregister(priv->fw_attr_kset);
979 
980 err_destroy_classdev:
981 	device_unregister(priv->fw_attr_dev);
982 
983 err_free_ida:
984 	ida_free(&lwmi_om_ida, priv->ida_id);
985 
986 err_no_ida:
987 	priv->ida_id = -EIDRM;
988 
989 	dev_warn(&priv->wdev->dev,
990 		 "failed to register firmware-attributes device: %d\n", err);
991 }
992 
993 /**
994  * lwmi_om_fw_attr_remove() - Unregister all capability data attribute groups
995  * @priv: the lenovo-wmi-other driver data.
996  */
lwmi_om_fw_attr_remove(struct lwmi_om_priv * priv)997 static void lwmi_om_fw_attr_remove(struct lwmi_om_priv *priv)
998 {
999 	if (priv->ida_id < 0)
1000 		return;
1001 
1002 	for (unsigned int i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++)
1003 		sysfs_remove_group(&priv->fw_attr_kset->kobj,
1004 				   cd01_attr_groups[i].attr_group);
1005 
1006 	kset_unregister(priv->fw_attr_kset);
1007 	device_unregister(priv->fw_attr_dev);
1008 	ida_free(&lwmi_om_ida, priv->ida_id);
1009 	priv->ida_id = -EIDRM;
1010 }
1011 
1012 /* ======== Self (master: lenovo-wmi-other) ======== */
1013 
1014 /**
1015  * lwmi_om_master_bind() - Bind all components of the other mode driver
1016  * @dev: The lenovo-wmi-other driver basic device.
1017  *
1018  * Call component_bind_all to bind the lenovo-wmi-capdata devices to the
1019  * lenovo-wmi-other master driver, with a callback to collect fan info from
1020  * capdata_fan. On success, assign the capability data list pointers to the
1021  * driver data struct for later access. These pointers are only valid while the
1022  * capdata interfaces exist. Finally, collect fan info from capdata00 and
1023  * register all firmware attribute groups. Note that the HWMON device is
1024  * registered only if all fan info is collected. Hence, it is not registered
1025  * here. See lwmi_om_fan_info_collect_cd00() and
1026  * lwmi_om_fan_info_collect_cd_fan().
1027  *
1028  * Return: 0 on success, or an error code.
1029  */
lwmi_om_master_bind(struct device * dev)1030 static int lwmi_om_master_bind(struct device *dev)
1031 {
1032 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
1033 	struct lwmi_cd_binder binder = {
1034 		.cd_fan_list_cb = lwmi_om_fan_info_collect_cd_fan,
1035 	};
1036 	int ret;
1037 
1038 	lwmi_om_fan_info_init(priv);
1039 
1040 	ret = component_bind_all(dev, &binder);
1041 	if (ret)
1042 		return ret;
1043 
1044 	priv->cd00_list = binder.cd00_list;
1045 	priv->cd01_list = binder.cd01_list;
1046 	if (!priv->cd00_list || !priv->cd01_list) {
1047 		component_unbind_all(dev, NULL);
1048 
1049 		return -ENODEV;
1050 	}
1051 
1052 	lwmi_om_fan_info_collect_cd00(priv);
1053 
1054 	lwmi_om_fw_attr_add(priv);
1055 
1056 	return 0;
1057 }
1058 
1059 /**
1060  * lwmi_om_master_unbind() - Unbind all components of the other mode driver
1061  * @dev: The lenovo-wmi-other driver basic device
1062  *
1063  * Unregister all firmware attribute groups and the HWMON device. Then call
1064  * component_unbind_all to unbind lenovo-wmi-capdata devices from the
1065  * lenovo-wmi-other master driver.
1066  */
lwmi_om_master_unbind(struct device * dev)1067 static void lwmi_om_master_unbind(struct device *dev)
1068 {
1069 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
1070 
1071 	lwmi_om_fw_attr_remove(priv);
1072 
1073 	lwmi_om_hwmon_remove(priv);
1074 
1075 	component_unbind_all(dev, NULL);
1076 }
1077 
1078 static const struct component_master_ops lwmi_om_master_ops = {
1079 	.bind = lwmi_om_master_bind,
1080 	.unbind = lwmi_om_master_unbind,
1081 };
1082 
lwmi_other_probe(struct wmi_device * wdev,const void * context)1083 static int lwmi_other_probe(struct wmi_device *wdev, const void *context)
1084 {
1085 	struct component_match *master_match = NULL;
1086 	struct lwmi_om_priv *priv;
1087 
1088 	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
1089 	if (!priv)
1090 		return -ENOMEM;
1091 
1092 	/* Sentinel for on-demand ida_free(). */
1093 	priv->ida_id = -EIDRM;
1094 
1095 	priv->wdev = wdev;
1096 	dev_set_drvdata(&wdev->dev, priv);
1097 
1098 	lwmi_cd_match_add_all(&wdev->dev, &master_match);
1099 	if (IS_ERR(master_match))
1100 		return PTR_ERR(master_match);
1101 
1102 	return component_master_add_with_match(&wdev->dev, &lwmi_om_master_ops,
1103 					       master_match);
1104 }
1105 
lwmi_other_remove(struct wmi_device * wdev)1106 static void lwmi_other_remove(struct wmi_device *wdev)
1107 {
1108 	component_master_del(&wdev->dev, &lwmi_om_master_ops);
1109 }
1110 
1111 static const struct wmi_device_id lwmi_other_id_table[] = {
1112 	{ LENOVO_OTHER_MODE_GUID, NULL },
1113 	{}
1114 };
1115 
1116 static struct wmi_driver lwmi_other_driver = {
1117 	.driver = {
1118 		.name = "lenovo_wmi_other",
1119 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
1120 	},
1121 	.id_table = lwmi_other_id_table,
1122 	.probe = lwmi_other_probe,
1123 	.remove = lwmi_other_remove,
1124 	.no_singleton = true,
1125 };
1126 
1127 module_wmi_driver(lwmi_other_driver);
1128 
1129 MODULE_IMPORT_NS("LENOVO_WMI_CAPDATA");
1130 MODULE_IMPORT_NS("LENOVO_WMI_HELPERS");
1131 MODULE_DEVICE_TABLE(wmi, lwmi_other_id_table);
1132 MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
1133 MODULE_AUTHOR("Rong Zhang <i@rong.moe>");
1134 MODULE_DESCRIPTION("Lenovo Other Mode WMI Driver");
1135 MODULE_LICENSE("GPL");
1136