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
353 err = lwmi_om_fan_get_set(priv, channel, &raw, true);
354 if (err)
355 return err;
356
357 priv->fan_info[channel].last_target = raw;
358 return 0;
359 }
360 }
361
362 return -EOPNOTSUPP;
363 }
364
365 static const struct hwmon_channel_info * const lwmi_om_hwmon_info[] = {
366 /* Must match LWMI_FAN_NR. */
367 HWMON_CHANNEL_INFO(fan,
368 HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
369 HWMON_F_MIN | HWMON_F_MAX,
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 NULL
377 };
378
379 static const struct hwmon_ops lwmi_om_hwmon_ops = {
380 .is_visible = lwmi_om_hwmon_is_visible,
381 .read = lwmi_om_hwmon_read,
382 .write = lwmi_om_hwmon_write,
383 };
384
385 static const struct hwmon_chip_info lwmi_om_hwmon_chip_info = {
386 .ops = &lwmi_om_hwmon_ops,
387 .info = lwmi_om_hwmon_info,
388 };
389
390 /**
391 * lwmi_om_hwmon_add() - Register HWMON device if all info is collected
392 * @priv: Driver private data
393 */
lwmi_om_hwmon_add(struct lwmi_om_priv * priv)394 static void lwmi_om_hwmon_add(struct lwmi_om_priv *priv)
395 {
396 int i, valid;
397
398 if (WARN_ON(priv->hwmon_dev))
399 return;
400
401 if (!priv->fan_flags.capdata00_collected || !priv->fan_flags.capdata_fan_collected) {
402 dev_dbg(&priv->wdev->dev, "HWMON registration pending (00: %d, fan: %d)\n",
403 priv->fan_flags.capdata00_collected,
404 priv->fan_flags.capdata_fan_collected);
405 return;
406 }
407
408 if (expose_all_fans)
409 dev_warn(&priv->wdev->dev, "all fans exposed. Use with caution\n");
410
411 if (relax_fan_constraint)
412 dev_warn(&priv->wdev->dev, "fan RPM constraint relaxed. Use with caution\n");
413
414 valid = 0;
415 for (i = 0; i < LWMI_FAN_NR; i++) {
416 if (!(priv->fan_info[i].supported & LWMI_SUPP_VALID))
417 continue;
418
419 valid++;
420
421 if (!expose_all_fans &&
422 (priv->fan_info[i].min_rpm < 0 || priv->fan_info[i].max_rpm < 0)) {
423 dev_dbg(&priv->wdev->dev, "missing RPM constraint for fan%d, hiding\n",
424 LWMI_FAN_ID(i));
425 priv->fan_info[i].supported = 0;
426 valid--;
427 }
428 }
429
430 if (valid == 0) {
431 dev_warn(&priv->wdev->dev,
432 "fan reporting/tuning is unsupported on this device\n");
433 return;
434 }
435
436 priv->hwmon_dev = hwmon_device_register_with_info(&priv->wdev->dev,
437 LWMI_OM_HWMON_NAME, priv,
438 &lwmi_om_hwmon_chip_info,
439 NULL);
440 if (IS_ERR(priv->hwmon_dev)) {
441 dev_warn(&priv->wdev->dev, "failed to register HWMON device: %ld\n",
442 PTR_ERR(priv->hwmon_dev));
443 priv->hwmon_dev = NULL;
444 return;
445 }
446
447 dev_dbg(&priv->wdev->dev, "registered HWMON device\n");
448 }
449
450 /**
451 * lwmi_om_hwmon_remove() - Unregister HWMON device
452 * @priv: Driver private data
453 *
454 * Unregisters the HWMON device if applicable.
455 */
lwmi_om_hwmon_remove(struct lwmi_om_priv * priv)456 static void lwmi_om_hwmon_remove(struct lwmi_om_priv *priv)
457 {
458 if (!priv->hwmon_dev)
459 return;
460
461 hwmon_device_unregister(priv->hwmon_dev);
462 priv->hwmon_dev = NULL;
463 }
464
465 /**
466 * lwmi_om_fan_info_init() - Initialzie fan info
467 * @priv: Driver private data
468 *
469 * lwmi_om_fan_info_collect_cd00() and lwmi_om_fan_info_collect_cd_fan() may be
470 * called in an arbitrary order. Hence, initializion must be done before.
471 */
lwmi_om_fan_info_init(struct lwmi_om_priv * priv)472 static void lwmi_om_fan_info_init(struct lwmi_om_priv *priv)
473 {
474 int i;
475
476 for (i = 0; i < LWMI_FAN_NR; i++) {
477 priv->fan_info[i] = (struct lwmi_fan_info) {
478 .supported = 0,
479 /*
480 * Assume 0 on probe as the EC resets all fans to auto mode on (re)boot.
481 *
482 * Note that S0ix (s2idle) preserves the RPM target, so we don't need
483 * suspend/resume callbacks. This behavior has not been tested on S3-
484 * capable devices, but I doubt if such devices even have this interface.
485 */
486 .last_target = 0,
487 .min_rpm = -ENODATA,
488 .max_rpm = -ENODATA,
489 };
490 }
491
492 priv->fan_flags.capdata00_collected = false;
493 priv->fan_flags.capdata_fan_collected = false;
494 }
495
496 /**
497 * lwmi_om_fan_info_collect_cd00() - Collect fan info from capdata 00
498 * @priv: Driver private data
499 */
lwmi_om_fan_info_collect_cd00(struct lwmi_om_priv * priv)500 static void lwmi_om_fan_info_collect_cd00(struct lwmi_om_priv *priv)
501 {
502 struct capdata00 capdata00;
503 int i, err;
504
505 dev_dbg(&priv->wdev->dev, "Collecting fan info from capdata00\n");
506
507 for (i = 0; i < LWMI_FAN_NR; i++) {
508 err = lwmi_cd00_get_data(priv->cd00_list, LWMI_ATTR_ID_FAN_RPM(i), &capdata00);
509 priv->fan_info[i].supported = err ? 0 : capdata00.supported;
510 }
511
512 priv->fan_flags.capdata00_collected = true;
513 lwmi_om_hwmon_add(priv);
514 }
515
516 /**
517 * lwmi_om_fan_info_collect_cd_fan() - Collect fan info from capdata fan
518 * @dev: Pointer to the lenovo-wmi-other device
519 * @cd_fan_list: Pointer to the capdata fan list
520 */
lwmi_om_fan_info_collect_cd_fan(struct device * dev,struct cd_list * cd_fan_list)521 static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list *cd_fan_list)
522 {
523 struct lwmi_om_priv *priv = dev_get_drvdata(dev);
524 struct capdata_fan capdata_fan;
525 int i, err;
526
527 dev_dbg(dev, "Collecting fan info from capdata_fan\n");
528
529 if (!cd_fan_list)
530 goto out;
531
532 for (i = 0; i < LWMI_FAN_NR; i++) {
533 err = lwmi_cd_fan_get_data(cd_fan_list, LWMI_FAN_ID(i), &capdata_fan);
534 if (err)
535 continue;
536
537 priv->fan_info[i].min_rpm = capdata_fan.min_rpm;
538 priv->fan_info[i].max_rpm = capdata_fan.max_rpm;
539 }
540
541 out:
542 priv->fan_flags.capdata_fan_collected = true;
543 lwmi_om_hwmon_add(priv);
544 }
545
546 /* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */
547
548 struct tunable_attr_01 {
549 struct capdata01 *capdata;
550 struct device *dev;
551 u32 feature_id;
552 u32 device_id;
553 u32 type_id;
554 };
555
556 static struct tunable_attr_01 ppt_pl1_spl = {
557 .device_id = LWMI_DEVICE_ID_CPU,
558 .feature_id = LWMI_FEATURE_ID_CPU_SPL,
559 .type_id = LWMI_TYPE_ID_NONE,
560 };
561
562 static struct tunable_attr_01 ppt_pl2_sppt = {
563 .device_id = LWMI_DEVICE_ID_CPU,
564 .feature_id = LWMI_FEATURE_ID_CPU_SPPT,
565 .type_id = LWMI_TYPE_ID_NONE,
566 };
567
568 static struct tunable_attr_01 ppt_pl3_fppt = {
569 .device_id = LWMI_DEVICE_ID_CPU,
570 .feature_id = LWMI_FEATURE_ID_CPU_FPPT,
571 .type_id = LWMI_TYPE_ID_NONE,
572 };
573
574 struct capdata01_attr_group {
575 const struct attribute_group *attr_group;
576 struct tunable_attr_01 *tunable_attr;
577 };
578
579 /**
580 * lwmi_om_register_notifier() - Add a notifier to the blocking notifier chain
581 * @nb: The notifier_block struct to register
582 *
583 * Call blocking_notifier_chain_register to register the notifier block to the
584 * lenovo-wmi-other driver notifier chain.
585 *
586 * Return: 0 on success, %-EEXIST on error.
587 */
lwmi_om_register_notifier(struct notifier_block * nb)588 int lwmi_om_register_notifier(struct notifier_block *nb)
589 {
590 return blocking_notifier_chain_register(&om_chain_head, nb);
591 }
592 EXPORT_SYMBOL_NS_GPL(lwmi_om_register_notifier, "LENOVO_WMI_OTHER");
593
594 /**
595 * lwmi_om_unregister_notifier() - Remove a notifier from the blocking notifier
596 * chain.
597 * @nb: The notifier_block struct to register
598 *
599 * Call blocking_notifier_chain_unregister to unregister the notifier block from the
600 * lenovo-wmi-other driver notifier chain.
601 *
602 * Return: 0 on success, %-ENOENT on error.
603 */
lwmi_om_unregister_notifier(struct notifier_block * nb)604 int lwmi_om_unregister_notifier(struct notifier_block *nb)
605 {
606 return blocking_notifier_chain_unregister(&om_chain_head, nb);
607 }
608 EXPORT_SYMBOL_NS_GPL(lwmi_om_unregister_notifier, "LENOVO_WMI_OTHER");
609
610 /**
611 * devm_lwmi_om_unregister_notifier() - Remove a notifier from the blocking
612 * notifier chain.
613 * @data: Void pointer to the notifier_block struct to register.
614 *
615 * Call lwmi_om_unregister_notifier to unregister the notifier block from the
616 * lenovo-wmi-other driver notifier chain.
617 *
618 * Return: 0 on success, %-ENOENT on error.
619 */
devm_lwmi_om_unregister_notifier(void * data)620 static void devm_lwmi_om_unregister_notifier(void *data)
621 {
622 struct notifier_block *nb = data;
623
624 lwmi_om_unregister_notifier(nb);
625 }
626
627 /**
628 * devm_lwmi_om_register_notifier() - Add a notifier to the blocking notifier
629 * chain.
630 * @dev: The parent device of the notifier_block struct.
631 * @nb: The notifier_block struct to register
632 *
633 * Call lwmi_om_register_notifier to register the notifier block to the
634 * lenovo-wmi-other driver notifier chain. Then add devm_lwmi_om_unregister_notifier
635 * as a device managed action to automatically unregister the notifier block
636 * upon parent device removal.
637 *
638 * Return: 0 on success, or an error code.
639 */
devm_lwmi_om_register_notifier(struct device * dev,struct notifier_block * nb)640 int devm_lwmi_om_register_notifier(struct device *dev,
641 struct notifier_block *nb)
642 {
643 int ret;
644
645 ret = lwmi_om_register_notifier(nb);
646 if (ret < 0)
647 return ret;
648
649 return devm_add_action_or_reset(dev, devm_lwmi_om_unregister_notifier,
650 nb);
651 }
652 EXPORT_SYMBOL_NS_GPL(devm_lwmi_om_register_notifier, "LENOVO_WMI_OTHER");
653
654 /**
655 * lwmi_om_notifier_call() - Call functions for the notifier call chain.
656 * @mode: Pointer to a thermal mode enum to retrieve the data from.
657 *
658 * Call blocking_notifier_call_chain to retrieve the thermal mode from the
659 * lenovo-wmi-gamezone driver.
660 *
661 * Return: 0 on success, or an error code.
662 */
lwmi_om_notifier_call(enum thermal_mode * mode)663 static int lwmi_om_notifier_call(enum thermal_mode *mode)
664 {
665 int ret;
666
667 ret = blocking_notifier_call_chain(&om_chain_head,
668 LWMI_GZ_GET_THERMAL_MODE, &mode);
669 if ((ret & ~NOTIFY_STOP_MASK) != NOTIFY_OK)
670 return -EINVAL;
671
672 return 0;
673 }
674
675 /* Attribute Methods */
676
677 /**
678 * int_type_show() - Emit the data type for an integer attribute
679 * @kobj: Pointer to the driver object.
680 * @kattr: Pointer to the attribute calling this function.
681 * @buf: The buffer to write to.
682 *
683 * Return: Number of characters written to buf.
684 */
int_type_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf)685 static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *kattr,
686 char *buf)
687 {
688 return sysfs_emit(buf, "integer\n");
689 }
690
691 /**
692 * attr_capdata01_show() - Get the value of the specified attribute property
693 *
694 * @kobj: Pointer to the driver object.
695 * @kattr: Pointer to the attribute calling this function.
696 * @buf: The buffer to write to.
697 * @tunable_attr: The attribute to be read.
698 * @prop: The property of this attribute to be read.
699 *
700 * Retrieves the given property from the capability data 01 struct for the
701 * specified attribute's "custom" thermal mode. This function is intended
702 * to be generic so it can be called from any integer attributes "_show"
703 * function.
704 *
705 * If the WMI is success the sysfs attribute is notified.
706 *
707 * Return: Either number of characters written to buf, or an error code.
708 */
attr_capdata01_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf,struct tunable_attr_01 * tunable_attr,enum attribute_property prop)709 static ssize_t attr_capdata01_show(struct kobject *kobj,
710 struct kobj_attribute *kattr, char *buf,
711 struct tunable_attr_01 *tunable_attr,
712 enum attribute_property prop)
713 {
714 struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
715 struct capdata01 capdata;
716 u32 attribute_id;
717 int value, ret;
718
719 attribute_id =
720 FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
721 FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
722 FIELD_PREP(LWMI_ATTR_MODE_ID_MASK,
723 LWMI_GZ_THERMAL_MODE_CUSTOM) |
724 FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
725
726 ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
727 if (ret)
728 return ret;
729
730 switch (prop) {
731 case DEFAULT_VAL:
732 value = capdata.default_value;
733 break;
734 case MAX_VAL:
735 value = capdata.max_value;
736 break;
737 case MIN_VAL:
738 value = capdata.min_value;
739 break;
740 case STEP_VAL:
741 value = capdata.step;
742 break;
743 default:
744 return -EINVAL;
745 }
746
747 return sysfs_emit(buf, "%d\n", value);
748 }
749
750 /**
751 * attr_current_value_store() - Set the current value of the given attribute
752 * @kobj: Pointer to the driver object.
753 * @kattr: Pointer to the attribute calling this function.
754 * @buf: The buffer to read from, this is parsed to `int` type.
755 * @count: Required by sysfs attribute macros, pass in from the callee attr.
756 * @tunable_attr: The attribute to be stored.
757 *
758 * Sets the value of the given attribute when operating under the "custom"
759 * smartfan profile. The current smartfan profile is retrieved from the
760 * lenovo-wmi-gamezone driver and error is returned if the result is not
761 * "custom". This function is intended to be generic so it can be called from
762 * any integer attribute's "_store" function. The integer to be sent to the WMI
763 * method is range checked and an error code is returned if out of range.
764 *
765 * If the value is valid and WMI is success, then the sysfs attribute is
766 * notified.
767 *
768 * Return: Either count, or an error code.
769 */
attr_current_value_store(struct kobject * kobj,struct kobj_attribute * kattr,const char * buf,size_t count,struct tunable_attr_01 * tunable_attr)770 static ssize_t attr_current_value_store(struct kobject *kobj,
771 struct kobj_attribute *kattr,
772 const char *buf, size_t count,
773 struct tunable_attr_01 *tunable_attr)
774 {
775 struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
776 struct wmi_method_args_32 args;
777 struct capdata01 capdata;
778 enum thermal_mode mode;
779 u32 attribute_id;
780 u32 value;
781 int ret;
782
783 ret = lwmi_om_notifier_call(&mode);
784 if (ret)
785 return ret;
786
787 if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM)
788 return -EBUSY;
789
790 attribute_id =
791 FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
792 FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
793 FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) |
794 FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
795
796 ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
797 if (ret)
798 return ret;
799
800 ret = kstrtouint(buf, 10, &value);
801 if (ret)
802 return ret;
803
804 if (value < capdata.min_value || value > capdata.max_value)
805 return -EINVAL;
806
807 args.arg0 = attribute_id;
808 args.arg1 = value;
809
810 ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,
811 (unsigned char *)&args, sizeof(args), NULL);
812 if (ret)
813 return ret;
814
815 return count;
816 };
817
818 /**
819 * attr_current_value_show() - Get the current value of the given attribute
820 * @kobj: Pointer to the driver object.
821 * @kattr: Pointer to the attribute calling this function.
822 * @buf: The buffer to write to.
823 * @tunable_attr: The attribute to be read.
824 *
825 * Retrieves the value of the given attribute for the current smartfan profile.
826 * The current smartfan profile is retrieved from the lenovo-wmi-gamezone driver.
827 * This function is intended to be generic so it can be called from any integer
828 * attribute's "_show" function.
829 *
830 * If the WMI is success the sysfs attribute is notified.
831 *
832 * Return: Either number of characters written to buf, or an error code.
833 */
attr_current_value_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf,struct tunable_attr_01 * tunable_attr)834 static ssize_t attr_current_value_show(struct kobject *kobj,
835 struct kobj_attribute *kattr, char *buf,
836 struct tunable_attr_01 *tunable_attr)
837 {
838 struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
839 struct wmi_method_args_32 args;
840 enum thermal_mode mode;
841 u32 attribute_id;
842 int retval;
843 int ret;
844
845 ret = lwmi_om_notifier_call(&mode);
846 if (ret)
847 return ret;
848
849 attribute_id =
850 FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
851 FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
852 FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) |
853 FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
854
855 args.arg0 = attribute_id;
856
857 ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
858 (unsigned char *)&args, sizeof(args),
859 &retval);
860 if (ret)
861 return ret;
862
863 return sysfs_emit(buf, "%d\n", retval);
864 }
865
866 /* Lenovo WMI Other Mode Attribute macros */
867 #define __LWMI_ATTR_RO(_func, _name) \
868 { \
869 .attr = { .name = __stringify(_name), .mode = 0444 }, \
870 .show = _func##_##_name##_show, \
871 }
872
873 #define __LWMI_ATTR_RO_AS(_name, _show) \
874 { \
875 .attr = { .name = __stringify(_name), .mode = 0444 }, \
876 .show = _show, \
877 }
878
879 #define __LWMI_ATTR_RW(_func, _name) \
880 __ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
881
882 /* Shows a formatted static variable */
883 #define __LWMI_ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \
884 static ssize_t _attrname##_##_prop##_show( \
885 struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
886 { \
887 return sysfs_emit(buf, _fmt, _val); \
888 } \
889 static struct kobj_attribute attr_##_attrname##_##_prop = \
890 __LWMI_ATTR_RO(_attrname, _prop)
891
892 /* Attribute current value read/write */
893 #define __LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname) \
894 static ssize_t _attrname##_current_value_store( \
895 struct kobject *kobj, struct kobj_attribute *kattr, \
896 const char *buf, size_t count) \
897 { \
898 return attr_current_value_store(kobj, kattr, buf, count, \
899 &_attrname); \
900 } \
901 static ssize_t _attrname##_current_value_show( \
902 struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
903 { \
904 return attr_current_value_show(kobj, kattr, buf, &_attrname); \
905 } \
906 static struct kobj_attribute attr_##_attrname##_current_value = \
907 __LWMI_ATTR_RW(_attrname, current_value)
908
909 /* Attribute property read only */
910 #define __LWMI_TUNABLE_RO_CAP01(_prop, _attrname, _prop_type) \
911 static ssize_t _attrname##_##_prop##_show( \
912 struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
913 { \
914 return attr_capdata01_show(kobj, kattr, buf, &_attrname, \
915 _prop_type); \
916 } \
917 static struct kobj_attribute attr_##_attrname##_##_prop = \
918 __LWMI_ATTR_RO(_attrname, _prop)
919
920 #define LWMI_ATTR_GROUP_TUNABLE_CAP01(_attrname, _fsname, _dispname) \
921 __LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname); \
922 __LWMI_TUNABLE_RO_CAP01(default_value, _attrname, DEFAULT_VAL); \
923 __LWMI_ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
924 __LWMI_TUNABLE_RO_CAP01(max_value, _attrname, MAX_VAL); \
925 __LWMI_TUNABLE_RO_CAP01(min_value, _attrname, MIN_VAL); \
926 __LWMI_TUNABLE_RO_CAP01(scalar_increment, _attrname, STEP_VAL); \
927 static struct kobj_attribute attr_##_attrname##_type = \
928 __LWMI_ATTR_RO_AS(type, int_type_show); \
929 static struct attribute *_attrname##_attrs[] = { \
930 &attr_##_attrname##_current_value.attr, \
931 &attr_##_attrname##_default_value.attr, \
932 &attr_##_attrname##_display_name.attr, \
933 &attr_##_attrname##_max_value.attr, \
934 &attr_##_attrname##_min_value.attr, \
935 &attr_##_attrname##_scalar_increment.attr, \
936 &attr_##_attrname##_type.attr, \
937 NULL, \
938 }; \
939 static const struct attribute_group _attrname##_attr_group = { \
940 .name = _fsname, .attrs = _attrname##_attrs \
941 }
942
943 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl, "ppt_pl1_spl",
944 "Set the CPU sustained power limit");
945 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt, "ppt_pl2_sppt",
946 "Set the CPU slow package power tracking limit");
947 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt, "ppt_pl3_fppt",
948 "Set the CPU fast package power tracking limit");
949
950 static struct capdata01_attr_group cd01_attr_groups[] = {
951 { &ppt_pl1_spl_attr_group, &ppt_pl1_spl },
952 { &ppt_pl2_sppt_attr_group, &ppt_pl2_sppt },
953 { &ppt_pl3_fppt_attr_group, &ppt_pl3_fppt },
954 {},
955 };
956
957 /**
958 * lwmi_om_fw_attr_add() - Register all firmware_attributes_class members
959 * @priv: The Other Mode driver data.
960 *
961 * Return: Either 0, or an error code.
962 */
lwmi_om_fw_attr_add(struct lwmi_om_priv * priv)963 static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
964 {
965 unsigned int i;
966 int err;
967
968 priv->ida_id = ida_alloc(&lwmi_om_ida, GFP_KERNEL);
969 if (priv->ida_id < 0)
970 return priv->ida_id;
971
972 priv->fw_attr_dev = device_create(&firmware_attributes_class, NULL,
973 MKDEV(0, 0), NULL, "%s-%u",
974 LWMI_OM_FW_ATTR_BASE_PATH,
975 priv->ida_id);
976 if (IS_ERR(priv->fw_attr_dev)) {
977 err = PTR_ERR(priv->fw_attr_dev);
978 goto err_free_ida;
979 }
980
981 priv->fw_attr_kset = kset_create_and_add("attributes", NULL,
982 &priv->fw_attr_dev->kobj);
983 if (!priv->fw_attr_kset) {
984 err = -ENOMEM;
985 goto err_destroy_classdev;
986 }
987
988 for (i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++) {
989 err = sysfs_create_group(&priv->fw_attr_kset->kobj,
990 cd01_attr_groups[i].attr_group);
991 if (err)
992 goto err_remove_groups;
993
994 cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev;
995 }
996 return 0;
997
998 err_remove_groups:
999 while (i--)
1000 sysfs_remove_group(&priv->fw_attr_kset->kobj,
1001 cd01_attr_groups[i].attr_group);
1002
1003 kset_unregister(priv->fw_attr_kset);
1004
1005 err_destroy_classdev:
1006 device_unregister(priv->fw_attr_dev);
1007
1008 err_free_ida:
1009 ida_free(&lwmi_om_ida, priv->ida_id);
1010 return err;
1011 }
1012
1013 /**
1014 * lwmi_om_fw_attr_remove() - Unregister all capability data attribute groups
1015 * @priv: the lenovo-wmi-other driver data.
1016 */
lwmi_om_fw_attr_remove(struct lwmi_om_priv * priv)1017 static void lwmi_om_fw_attr_remove(struct lwmi_om_priv *priv)
1018 {
1019 for (unsigned int i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++)
1020 sysfs_remove_group(&priv->fw_attr_kset->kobj,
1021 cd01_attr_groups[i].attr_group);
1022
1023 kset_unregister(priv->fw_attr_kset);
1024 device_unregister(priv->fw_attr_dev);
1025 }
1026
1027 /* ======== Self (master: lenovo-wmi-other) ======== */
1028
1029 /**
1030 * lwmi_om_master_bind() - Bind all components of the other mode driver
1031 * @dev: The lenovo-wmi-other driver basic device.
1032 *
1033 * Call component_bind_all to bind the lenovo-wmi-capdata devices to the
1034 * lenovo-wmi-other master driver, with a callback to collect fan info from
1035 * capdata_fan. On success, assign the capability data list pointers to the
1036 * driver data struct for later access. These pointers are only valid while the
1037 * capdata interfaces exist. Finally, collect fan info from capdata00 and
1038 * register all firmware attribute groups. Note that the HWMON device is
1039 * registered only if all fan info is collected. Hence, it is not registered
1040 * here. See lwmi_om_fan_info_collect_cd00() and
1041 * lwmi_om_fan_info_collect_cd_fan().
1042 *
1043 * Return: 0 on success, or an error code.
1044 */
lwmi_om_master_bind(struct device * dev)1045 static int lwmi_om_master_bind(struct device *dev)
1046 {
1047 struct lwmi_om_priv *priv = dev_get_drvdata(dev);
1048 struct lwmi_cd_binder binder = {
1049 .cd_fan_list_cb = lwmi_om_fan_info_collect_cd_fan,
1050 };
1051 int ret;
1052
1053 lwmi_om_fan_info_init(priv);
1054
1055 ret = component_bind_all(dev, &binder);
1056 if (ret)
1057 return ret;
1058
1059 priv->cd00_list = binder.cd00_list;
1060 priv->cd01_list = binder.cd01_list;
1061 if (!priv->cd00_list || !priv->cd01_list)
1062 return -ENODEV;
1063
1064 lwmi_om_fan_info_collect_cd00(priv);
1065
1066 return lwmi_om_fw_attr_add(priv);
1067 }
1068
1069 /**
1070 * lwmi_om_master_unbind() - Unbind all components of the other mode driver
1071 * @dev: The lenovo-wmi-other driver basic device
1072 *
1073 * Unregister all firmware attribute groups and the HWMON device. Then call
1074 * component_unbind_all to unbind lenovo-wmi-capdata devices from the
1075 * lenovo-wmi-other master driver.
1076 */
lwmi_om_master_unbind(struct device * dev)1077 static void lwmi_om_master_unbind(struct device *dev)
1078 {
1079 struct lwmi_om_priv *priv = dev_get_drvdata(dev);
1080
1081 lwmi_om_fw_attr_remove(priv);
1082
1083 lwmi_om_hwmon_remove(priv);
1084
1085 component_unbind_all(dev, NULL);
1086 }
1087
1088 static const struct component_master_ops lwmi_om_master_ops = {
1089 .bind = lwmi_om_master_bind,
1090 .unbind = lwmi_om_master_unbind,
1091 };
1092
lwmi_other_probe(struct wmi_device * wdev,const void * context)1093 static int lwmi_other_probe(struct wmi_device *wdev, const void *context)
1094 {
1095 struct component_match *master_match = NULL;
1096 struct lwmi_om_priv *priv;
1097
1098 priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
1099 if (!priv)
1100 return -ENOMEM;
1101
1102 /* Sentinel for on-demand ida_free(). */
1103 priv->ida_id = -EIDRM;
1104
1105 priv->wdev = wdev;
1106 dev_set_drvdata(&wdev->dev, priv);
1107
1108 lwmi_cd_match_add_all(&wdev->dev, &master_match);
1109 if (IS_ERR(master_match))
1110 return PTR_ERR(master_match);
1111
1112 return component_master_add_with_match(&wdev->dev, &lwmi_om_master_ops,
1113 master_match);
1114 }
1115
lwmi_other_remove(struct wmi_device * wdev)1116 static void lwmi_other_remove(struct wmi_device *wdev)
1117 {
1118 struct lwmi_om_priv *priv = dev_get_drvdata(&wdev->dev);
1119
1120 component_master_del(&wdev->dev, &lwmi_om_master_ops);
1121
1122 /* No IDA to free if the driver is never bound to its components. */
1123 if (priv->ida_id >= 0)
1124 ida_free(&lwmi_om_ida, priv->ida_id);
1125 }
1126
1127 static const struct wmi_device_id lwmi_other_id_table[] = {
1128 { LENOVO_OTHER_MODE_GUID, NULL },
1129 {}
1130 };
1131
1132 static struct wmi_driver lwmi_other_driver = {
1133 .driver = {
1134 .name = "lenovo_wmi_other",
1135 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
1136 },
1137 .id_table = lwmi_other_id_table,
1138 .probe = lwmi_other_probe,
1139 .remove = lwmi_other_remove,
1140 .no_singleton = true,
1141 };
1142
1143 module_wmi_driver(lwmi_other_driver);
1144
1145 MODULE_IMPORT_NS("LENOVO_WMI_CAPDATA");
1146 MODULE_IMPORT_NS("LENOVO_WMI_HELPERS");
1147 MODULE_DEVICE_TABLE(wmi, lwmi_other_id_table);
1148 MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
1149 MODULE_AUTHOR("Rong Zhang <i@rong.moe>");
1150 MODULE_DESCRIPTION("Lenovo Other Mode WMI Driver");
1151 MODULE_LICENSE("GPL");
1152