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