xref: /linux/drivers/platform/x86/lenovo/wmi-capdata.c (revision 4c2cd91bff6371b58e672e8791c3bfa70c1b821f)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Lenovo Capability Data WMI Data Block driver.
4  *
5  * Lenovo Capability Data provides information on tunable attributes used by
6  * the "Other Mode" WMI interface.
7  *
8  * Capability Data 00 includes if the attribute is supported by the hardware,
9  * and the default_value. All attributes are independent of thermal modes.
10  *
11  * Capability Data 01 includes if the attribute is supported by the hardware,
12  * and the default_value, max_value, min_value, and step increment. Each
13  * attribute has multiple pages, one for each of the thermal modes managed by
14  * the Gamezone interface.
15  *
16  * Fan Test Data includes the max/min fan speed RPM for each fan. This is
17  * reference data for self-test. If the fan is in good condition, it is capable
18  * to spin faster than max RPM or slower than min RPM.
19  *
20  * Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com>
21  *   - Initial implementation (formerly named lenovo-wmi-capdata01)
22  *
23  * Copyright (C) 2025 Rong Zhang <i@rong.moe>
24  *   - Unified implementation
25  */
26 
27 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28 
29 #include <linux/acpi.h>
30 #include <linux/bug.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/dev_printk.h>
36 #include <linux/err.h>
37 #include <linux/export.h>
38 #include <linux/gfp_types.h>
39 #include <linux/limits.h>
40 #include <linux/module.h>
41 #include <linux/mutex.h>
42 #include <linux/mutex_types.h>
43 #include <linux/notifier.h>
44 #include <linux/overflow.h>
45 #include <linux/stddef.h>
46 #include <linux/types.h>
47 #include <linux/wmi.h>
48 
49 #include "wmi-capdata.h"
50 #include "wmi-helpers.h"
51 
52 #define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"
53 #define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"
54 #define LENOVO_FAN_TEST_DATA_GUID "B642801B-3D21-45DE-90AE-6E86F164FB21"
55 
56 #define ACPI_AC_NOTIFY_STATUS 0x80
57 
58 #define LWMI_FEATURE_ID_FAN_TEST 0x05
59 
60 #define LWMI_ATTR_ID_FAN_TEST                                      \
61 	lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_TEST, \
62 		     LWMI_GZ_THERMAL_MODE_NONE, LWMI_TYPE_ID_NONE)
63 
64 enum lwmi_cd_type {
65 	LENOVO_CAPABILITY_DATA_00,
66 	LENOVO_CAPABILITY_DATA_01,
67 	LENOVO_FAN_TEST_DATA,
68 	CD_TYPE_NONE = -1,
69 };
70 
71 #define LWMI_CD_TABLE_ITEM(_type)		\
72 	[_type] = {				\
73 		.name = #_type,			\
74 		.type = _type,			\
75 	}
76 
77 static const struct lwmi_cd_info {
78 	const char *name;
79 	enum lwmi_cd_type type;
80 } lwmi_cd_table[] = {
81 	LWMI_CD_TABLE_ITEM(LENOVO_CAPABILITY_DATA_00),
82 	LWMI_CD_TABLE_ITEM(LENOVO_CAPABILITY_DATA_01),
83 	LWMI_CD_TABLE_ITEM(LENOVO_FAN_TEST_DATA),
84 };
85 
86 struct lwmi_cd_priv {
87 	struct notifier_block acpi_nb; /* ACPI events */
88 	struct wmi_device *wdev;
89 	struct cd_list *list;
90 
91 	/*
92 	 * A capdata device may be a component master of another capdata device.
93 	 * E.g., lenovo-wmi-other <-> capdata00 <-> capdata_fan
94 	 *       |- master            |- component
95 	 *                            |- sub-master
96 	 *                                          |- sub-component
97 	 */
98 	struct lwmi_cd_sub_master_priv {
99 		struct device *master_dev;
100 		cd_list_cb_t master_cb;
101 		struct cd_list *sub_component_list; /* ERR_PTR(-ENODEV) implies no sub-component. */
102 		bool registered;                    /* Has the sub-master been registered? */
103 	} *sub_master;
104 };
105 
106 struct cd_list {
107 	struct mutex list_mutex; /* list R/W mutex */
108 	enum lwmi_cd_type type;
109 	u8 count;
110 
111 	union {
112 		DECLARE_FLEX_ARRAY(struct capdata00, cd00);
113 		DECLARE_FLEX_ARRAY(struct capdata01, cd01);
114 		DECLARE_FLEX_ARRAY(struct capdata_fan, cd_fan);
115 	};
116 };
117 
118 static struct wmi_driver lwmi_cd_driver;
119 
120 /**
121  * lwmi_cd_match() - Match rule for the master driver.
122  * @dev: Pointer to the capability data parent device.
123  * @type: Pointer to capability data type (enum lwmi_cd_type *) to match.
124  *
125  * Return: int.
126  */
lwmi_cd_match(struct device * dev,void * type)127 static int lwmi_cd_match(struct device *dev, void *type)
128 {
129 	struct lwmi_cd_priv *priv;
130 
131 	if (dev->driver != &lwmi_cd_driver.driver)
132 		return false;
133 
134 	priv = dev_get_drvdata(dev);
135 	return priv->list->type == *(enum lwmi_cd_type *)type;
136 }
137 
138 /**
139  * lwmi_cd_match_add_all() - Add all match rule for the master driver.
140  * @master: Pointer to the master device.
141  * @matchptr: Pointer to the returned component_match pointer.
142  *
143  * Adds all component matches to the list stored in @matchptr for the @master
144  * device. @matchptr must be initialized to NULL.
145  */
lwmi_cd_match_add_all(struct device * master,struct component_match ** matchptr)146 void lwmi_cd_match_add_all(struct device *master, struct component_match **matchptr)
147 {
148 	int i;
149 
150 	if (WARN_ON(*matchptr))
151 		return;
152 
153 	for (i = 0; i < ARRAY_SIZE(lwmi_cd_table); i++) {
154 		/* Skip sub-components. */
155 		if (lwmi_cd_table[i].type == LENOVO_FAN_TEST_DATA)
156 			continue;
157 
158 		component_match_add(master, matchptr, lwmi_cd_match,
159 				    (void *)&lwmi_cd_table[i].type);
160 		if (IS_ERR(*matchptr))
161 			return;
162 	}
163 }
164 EXPORT_SYMBOL_NS_GPL(lwmi_cd_match_add_all, "LENOVO_WMI_CAPDATA");
165 
166 /**
167  * lwmi_cd_call_master_cb() - Call the master callback for the sub-component.
168  * @priv: Pointer to the capability data private data.
169  *
170  * Call the master callback and pass the sub-component list to it if the
171  * dependency chain (master <-> sub-master <-> sub-component) is complete.
172  */
lwmi_cd_call_master_cb(struct lwmi_cd_priv * priv)173 static void lwmi_cd_call_master_cb(struct lwmi_cd_priv *priv)
174 {
175 	struct cd_list *sub_component_list = priv->sub_master->sub_component_list;
176 
177 	/*
178 	 * Call the callback only if the dependency chain is ready:
179 	 * - Binding between master and sub-master: fills master_dev and master_cb
180 	 * - Binding between sub-master and sub-component: fills sub_component_list
181 	 *
182 	 * If a binding has been unbound before the other binding is bound, the
183 	 * corresponding members filled by the former are guaranteed to be cleared.
184 	 *
185 	 * This function is only called in bind callbacks, and the component
186 	 * framework guarantees bind/unbind callbacks may never execute
187 	 * simultaneously, which implies that it's impossible to have a race
188 	 * condition.
189 	 *
190 	 * Hence, this check is sufficient to ensure that the callback is called
191 	 * at most once and with the correct state, without relying on a specific
192 	 * sequence of binding establishment.
193 	 */
194 	if (!sub_component_list ||
195 	    !priv->sub_master->master_dev ||
196 	    !priv->sub_master->master_cb)
197 		return;
198 
199 	if (PTR_ERR(sub_component_list) == -ENODEV)
200 		sub_component_list = NULL;
201 	else if (WARN_ON(IS_ERR(sub_component_list)))
202 		return;
203 
204 	priv->sub_master->master_cb(priv->sub_master->master_dev,
205 				    sub_component_list);
206 
207 	/*
208 	 * Userspace may unbind a device from its driver and bind it again
209 	 * through sysfs. Let's call this operation "reprobe" to distinguish it
210 	 * from component "rebind".
211 	 *
212 	 * When reprobing capdata00/01 or the master device, the master device
213 	 * is unbound from us with appropriate cleanup before we bind to it and
214 	 * call master_cb. Everything is fine in this case.
215 	 *
216 	 * When reprobing capdata_fan, the master device has never been unbound
217 	 * from us (hence no cleanup is done)[1], but we call master_cb the
218 	 * second time. To solve this issue, we clear master_cb and master_dev
219 	 * so we won't call master_cb twice while a binding is still complete.
220 	 *
221 	 * Note that we can't clear sub_component_list, otherwise reprobing
222 	 * capdata01 or the master device causes master_cb to be never called
223 	 * after we rebind to the master device.
224 	 *
225 	 * [1]: The master device does not need capdata_fan in run time, so
226 	 * losing capdata_fan will not break the binding to the master device.
227 	 */
228 	priv->sub_master->master_cb = NULL;
229 	priv->sub_master->master_dev = NULL;
230 }
231 
232 /**
233  * lwmi_cd_component_bind() - Bind component to master device.
234  * @cd_dev: Pointer to the lenovo-wmi-capdata driver parent device.
235  * @om_dev: Pointer to the lenovo-wmi-other driver parent device.
236  * @data: lwmi_cd_binder object pointer used to return the capability data.
237  *
238  * On lenovo-wmi-other's master bind, provide a pointer to the local capdata
239  * list. This is used to call lwmi_cd*_get_data to look up attribute data
240  * from the lenovo-wmi-other driver.
241  *
242  * If cd_dev is a sub-master, try to call the master callback.
243  *
244  * Return: 0
245  */
lwmi_cd_component_bind(struct device * cd_dev,struct device * om_dev,void * data)246 static int lwmi_cd_component_bind(struct device *cd_dev,
247 				  struct device *om_dev, void *data)
248 {
249 	struct lwmi_cd_priv *priv = dev_get_drvdata(cd_dev);
250 	struct lwmi_cd_binder *binder = data;
251 
252 	switch (priv->list->type) {
253 	case LENOVO_CAPABILITY_DATA_00:
254 		binder->cd00_list = priv->list;
255 
256 		priv->sub_master->master_dev = om_dev;
257 		priv->sub_master->master_cb = binder->cd_fan_list_cb;
258 		lwmi_cd_call_master_cb(priv);
259 
260 		break;
261 	case LENOVO_CAPABILITY_DATA_01:
262 		binder->cd01_list = priv->list;
263 		break;
264 	default:
265 		return -EINVAL;
266 	}
267 
268 	return 0;
269 }
270 
271 /**
272  * lwmi_cd_component_unbind() - Unbind component to master device.
273  * @cd_dev: Pointer to the lenovo-wmi-capdata driver parent device.
274  * @om_dev: Pointer to the lenovo-wmi-other driver parent device.
275  * @data: Unused.
276  *
277  * If cd_dev is a sub-master, clear the collected data from the master device to
278  * prevent the binding establishment between the sub-master and the sub-
279  * component (if it's about to happen) from calling the master callback.
280  */
lwmi_cd_component_unbind(struct device * cd_dev,struct device * om_dev,void * data)281 static void lwmi_cd_component_unbind(struct device *cd_dev,
282 				     struct device *om_dev, void *data)
283 {
284 	struct lwmi_cd_priv *priv = dev_get_drvdata(cd_dev);
285 
286 	switch (priv->list->type) {
287 	case LENOVO_CAPABILITY_DATA_00:
288 		priv->sub_master->master_dev = NULL;
289 		priv->sub_master->master_cb = NULL;
290 		return;
291 	default:
292 		return;
293 	}
294 }
295 
296 static const struct component_ops lwmi_cd_component_ops = {
297 	.bind = lwmi_cd_component_bind,
298 	.unbind = lwmi_cd_component_unbind,
299 };
300 
301 /**
302  * lwmi_cd_sub_master_bind() - Bind sub-component of sub-master device
303  * @dev: The sub-master capdata basic device.
304  *
305  * Call component_bind_all to bind the sub-component device to the sub-master
306  * device. On success, collect the pointer to the sub-component list and try
307  * to call the master callback.
308  *
309  * Return: 0 on success, or an error code.
310  */
lwmi_cd_sub_master_bind(struct device * dev)311 static int lwmi_cd_sub_master_bind(struct device *dev)
312 {
313 	struct lwmi_cd_priv *priv = dev_get_drvdata(dev);
314 	struct cd_list *sub_component_list;
315 	int ret;
316 
317 	ret = component_bind_all(dev, &sub_component_list);
318 	if (ret)
319 		return ret;
320 
321 	priv->sub_master->sub_component_list = sub_component_list;
322 	lwmi_cd_call_master_cb(priv);
323 
324 	return 0;
325 }
326 
327 /**
328  * lwmi_cd_sub_master_unbind() - Unbind sub-component of sub-master device
329  * @dev: The sub-master capdata basic device
330  *
331  * Clear the collected pointer to the sub-component list to prevent the binding
332  * establishment between the sub-master and the sub-component (if it's about to
333  * happen) from calling the master callback. Then, call component_unbind_all to
334  * unbind the sub-component device from the sub-master device.
335  */
lwmi_cd_sub_master_unbind(struct device * dev)336 static void lwmi_cd_sub_master_unbind(struct device *dev)
337 {
338 	struct lwmi_cd_priv *priv = dev_get_drvdata(dev);
339 
340 	priv->sub_master->sub_component_list = NULL;
341 
342 	component_unbind_all(dev, NULL);
343 }
344 
345 static const struct component_master_ops lwmi_cd_sub_master_ops = {
346 	.bind = lwmi_cd_sub_master_bind,
347 	.unbind = lwmi_cd_sub_master_unbind,
348 };
349 
350 /**
351  * lwmi_cd_sub_master_add() - Register a sub-master with its sub-component
352  * @priv: Pointer to the sub-master capdata device private data.
353  * @sub_component_type: Type of the sub-component.
354  *
355  * Match the sub-component type and register the current capdata device as a
356  * sub-master. If the given sub-component type is CD_TYPE_NONE, mark the sub-
357  * component as non-existent without registering sub-master.
358  *
359  * Return: 0 on success, or an error code.
360  */
lwmi_cd_sub_master_add(struct lwmi_cd_priv * priv,enum lwmi_cd_type sub_component_type)361 static int lwmi_cd_sub_master_add(struct lwmi_cd_priv *priv,
362 				  enum lwmi_cd_type sub_component_type)
363 {
364 	struct component_match *master_match = NULL;
365 	int ret;
366 
367 	priv->sub_master = devm_kzalloc(&priv->wdev->dev, sizeof(*priv->sub_master), GFP_KERNEL);
368 	if (!priv->sub_master)
369 		return -ENOMEM;
370 
371 	if (sub_component_type == CD_TYPE_NONE) {
372 		/* The master callback will be called with NULL on bind. */
373 		priv->sub_master->sub_component_list = ERR_PTR(-ENODEV);
374 		priv->sub_master->registered = false;
375 		return 0;
376 	}
377 
378 	/*
379 	 * lwmi_cd_match() needs a pointer to enum lwmi_cd_type, but on-stack
380 	 * data cannot be used here. Steal one from lwmi_cd_table.
381 	 */
382 	component_match_add(&priv->wdev->dev, &master_match, lwmi_cd_match,
383 			    (void *)&lwmi_cd_table[sub_component_type].type);
384 	if (IS_ERR(master_match))
385 		return PTR_ERR(master_match);
386 
387 	ret = component_master_add_with_match(&priv->wdev->dev, &lwmi_cd_sub_master_ops,
388 					      master_match);
389 	if (ret)
390 		return ret;
391 
392 	priv->sub_master->registered = true;
393 	return 0;
394 }
395 
396 /**
397  * lwmi_cd_sub_master_del() - Unregister a sub-master if it's registered
398  * @priv: Pointer to the sub-master capdata device private data.
399  */
lwmi_cd_sub_master_del(struct lwmi_cd_priv * priv)400 static void lwmi_cd_sub_master_del(struct lwmi_cd_priv *priv)
401 {
402 	if (!priv->sub_master->registered)
403 		return;
404 
405 	component_master_del(&priv->wdev->dev, &lwmi_cd_sub_master_ops);
406 	priv->sub_master->registered = false;
407 }
408 
409 /**
410  * lwmi_cd_sub_component_bind() - Bind sub-component to sub-master device.
411  * @sc_dev: Pointer to the sub-component capdata parent device.
412  * @sm_dev: Pointer to the sub-master capdata parent device.
413  * @data: Pointer used to return the capability data list pointer.
414  *
415  * On sub-master's bind, provide a pointer to the local capdata list.
416  * This is used by the sub-master to call the master callback.
417  *
418  * Return: 0
419  */
lwmi_cd_sub_component_bind(struct device * sc_dev,struct device * sm_dev,void * data)420 static int lwmi_cd_sub_component_bind(struct device *sc_dev,
421 				      struct device *sm_dev, void *data)
422 {
423 	struct lwmi_cd_priv *priv = dev_get_drvdata(sc_dev);
424 	struct cd_list **listp = data;
425 
426 	*listp = priv->list;
427 
428 	return 0;
429 }
430 
431 static const struct component_ops lwmi_cd_sub_component_ops = {
432 	.bind = lwmi_cd_sub_component_bind,
433 };
434 
435 /*
436  * lwmi_cd*_get_data - Get the data of the specified attribute
437  * @list: The lenovo-wmi-capdata pointer to its cd_list struct.
438  * @attribute_id: The capdata attribute ID to be found.
439  * @output: Pointer to a capdata* struct to return the data.
440  *
441  * Retrieves the capability data struct pointer for the given
442  * attribute.
443  *
444  * Return: 0 on success, or -EINVAL.
445  */
446 #define DEF_LWMI_CDXX_GET_DATA(_cdxx, _cd_type, _output_t)					\
447 	int lwmi_##_cdxx##_get_data(struct cd_list *list, u32 attribute_id, _output_t *output)	\
448 	{											\
449 		u8 idx;										\
450 												\
451 		if (WARN_ON(list->type != _cd_type))						\
452 			return -EINVAL;								\
453 												\
454 		guard(mutex)(&list->list_mutex);						\
455 		for (idx = 0; idx < list->count; idx++) {					\
456 			if (list->_cdxx[idx].id != attribute_id)				\
457 				continue;							\
458 			memcpy(output, &list->_cdxx[idx], sizeof(list->_cdxx[idx]));		\
459 			return 0;								\
460 		}										\
461 		return -EINVAL;									\
462 	}
463 
464 DEF_LWMI_CDXX_GET_DATA(cd00, LENOVO_CAPABILITY_DATA_00, struct capdata00);
465 EXPORT_SYMBOL_NS_GPL(lwmi_cd00_get_data, "LENOVO_WMI_CAPDATA");
466 
467 DEF_LWMI_CDXX_GET_DATA(cd01, LENOVO_CAPABILITY_DATA_01, struct capdata01);
468 EXPORT_SYMBOL_NS_GPL(lwmi_cd01_get_data, "LENOVO_WMI_CAPDATA");
469 
470 DEF_LWMI_CDXX_GET_DATA(cd_fan, LENOVO_FAN_TEST_DATA, struct capdata_fan);
471 EXPORT_SYMBOL_NS_GPL(lwmi_cd_fan_get_data, "LENOVO_WMI_CAPDATA");
472 
473 /**
474  * lwmi_cd_cache() - Cache all WMI data block information
475  * @priv: lenovo-wmi-capdata driver data.
476  *
477  * Loop through each WMI data block and cache the data.
478  *
479  * Return: 0 on success, or an error.
480  */
lwmi_cd_cache(struct lwmi_cd_priv * priv)481 static int lwmi_cd_cache(struct lwmi_cd_priv *priv)
482 {
483 	size_t size;
484 	int idx;
485 	void *p;
486 
487 	switch (priv->list->type) {
488 	case LENOVO_CAPABILITY_DATA_00:
489 		p = &priv->list->cd00[0];
490 		size = sizeof(priv->list->cd00[0]);
491 		break;
492 	case LENOVO_CAPABILITY_DATA_01:
493 		p = &priv->list->cd01[0];
494 		size = sizeof(priv->list->cd01[0]);
495 		break;
496 	case LENOVO_FAN_TEST_DATA:
497 		/* Done by lwmi_cd_alloc() => lwmi_cd_fan_list_alloc_cache(). */
498 		return 0;
499 	default:
500 		return -EINVAL;
501 	}
502 
503 	guard(mutex)(&priv->list->list_mutex);
504 	for (idx = 0; idx < priv->list->count; idx++, p += size) {
505 		union acpi_object *ret_obj __free(kfree) = NULL;
506 
507 		ret_obj = wmidev_block_query(priv->wdev, idx);
508 		if (!ret_obj)
509 			return -ENODEV;
510 
511 		if (ret_obj->type != ACPI_TYPE_BUFFER ||
512 		    ret_obj->buffer.length < size)
513 			continue;
514 
515 		memcpy(p, ret_obj->buffer.pointer, size);
516 	}
517 
518 	return 0;
519 }
520 
521 /**
522  * lwmi_cd_fan_list_alloc_cache() - Alloc and cache Fan Test Data list
523  * @priv: lenovo-wmi-capdata driver data.
524  * @listptr: Pointer to returned cd_list pointer.
525  *
526  * Return: count of fans found, or an error.
527  */
lwmi_cd_fan_list_alloc_cache(struct lwmi_cd_priv * priv,struct cd_list ** listptr)528 static int lwmi_cd_fan_list_alloc_cache(struct lwmi_cd_priv *priv, struct cd_list **listptr)
529 {
530 	struct cd_list *list;
531 	size_t size;
532 	u32 count;
533 	int idx;
534 
535 	/* Emit unaligned access to u8 buffer with __packed. */
536 	struct cd_fan_block {
537 		u32 nr;
538 		u32 data[]; /* id[nr], max_rpm[nr], min_rpm[nr] */
539 	} __packed * block;
540 
541 	union acpi_object *ret_obj __free(kfree) = wmidev_block_query(priv->wdev, 0);
542 	if (!ret_obj)
543 		return -ENODEV;
544 
545 	if (ret_obj->type == ACPI_TYPE_BUFFER) {
546 		block = (struct cd_fan_block *)ret_obj->buffer.pointer;
547 		size = ret_obj->buffer.length;
548 
549 		count = size >= sizeof(*block) ? block->nr : 0;
550 		if (size < struct_size(block, data, count * 3)) {
551 			dev_warn(&priv->wdev->dev,
552 				 "incomplete fan test data block: %zu < %zu, ignoring\n",
553 				 size, struct_size(block, data, count * 3));
554 			count = 0;
555 		} else if (count > U8_MAX) {
556 			dev_warn(&priv->wdev->dev,
557 				 "too many fans reported: %u > %u, truncating\n",
558 				 count, U8_MAX);
559 			count = U8_MAX;
560 		}
561 	} else {
562 		/*
563 		 * This is usually caused by a dummy ACPI method. Do not return an error
564 		 * as failing to probe this device will result in sub-master device being
565 		 * unbound. This behavior aligns with lwmi_cd_cache().
566 		 */
567 		count = 0;
568 	}
569 
570 	list = devm_kzalloc(&priv->wdev->dev, struct_size(list, cd_fan, count), GFP_KERNEL);
571 	if (!list)
572 		return -ENOMEM;
573 
574 	for (idx = 0; idx < count; idx++) {
575 		/* Do not calculate array index using count, as it may be truncated. */
576 		list->cd_fan[idx] = (struct capdata_fan) {
577 			.id      = block->data[idx],
578 			.max_rpm = block->data[idx + block->nr],
579 			.min_rpm = block->data[idx + (2 * block->nr)],
580 		};
581 	}
582 
583 	*listptr = list;
584 	return count;
585 }
586 
587 /**
588  * lwmi_cd_alloc() - Allocate a cd_list struct in drvdata
589  * @priv: lenovo-wmi-capdata driver data.
590  * @type: The type of capability data.
591  *
592  * Allocate a cd_list struct large enough to contain data from all WMI data
593  * blocks provided by the interface.
594  *
595  * Return: 0 on success, or an error.
596  */
lwmi_cd_alloc(struct lwmi_cd_priv * priv,enum lwmi_cd_type type)597 static int lwmi_cd_alloc(struct lwmi_cd_priv *priv, enum lwmi_cd_type type)
598 {
599 	struct cd_list *list;
600 	size_t list_size;
601 	int count, ret;
602 
603 	count = wmidev_instance_count(priv->wdev);
604 
605 	switch (type) {
606 	case LENOVO_CAPABILITY_DATA_00:
607 		list_size = struct_size(list, cd00, count);
608 		break;
609 	case LENOVO_CAPABILITY_DATA_01:
610 		list_size = struct_size(list, cd01, count);
611 		break;
612 	case LENOVO_FAN_TEST_DATA:
613 		count = lwmi_cd_fan_list_alloc_cache(priv, &list);
614 		if (count < 0)
615 			return count;
616 
617 		goto got_list;
618 	default:
619 		return -EINVAL;
620 	}
621 
622 	list = devm_kzalloc(&priv->wdev->dev, list_size, GFP_KERNEL);
623 	if (!list)
624 		return -ENOMEM;
625 
626 got_list:
627 	ret = devm_mutex_init(&priv->wdev->dev, &list->list_mutex);
628 	if (ret)
629 		return ret;
630 
631 	list->type = type;
632 	list->count = count;
633 	priv->list = list;
634 
635 	return 0;
636 }
637 
638 /**
639  * lwmi_cd_setup() - Cache all WMI data block information
640  * @priv: lenovo-wmi-capdata driver data.
641  * @type: The type of capability data.
642  *
643  * Allocate a cd_list struct large enough to contain data from all WMI data
644  * blocks provided by the interface. Then loop through each data block and
645  * cache the data.
646  *
647  * Return: 0 on success, or an error code.
648  */
lwmi_cd_setup(struct lwmi_cd_priv * priv,enum lwmi_cd_type type)649 static int lwmi_cd_setup(struct lwmi_cd_priv *priv, enum lwmi_cd_type type)
650 {
651 	int ret;
652 
653 	ret = lwmi_cd_alloc(priv, type);
654 	if (ret)
655 		return ret;
656 
657 	return lwmi_cd_cache(priv);
658 }
659 
660 /**
661  * lwmi_cd01_notifier_call() - Call method for cd01 notifier.
662  * block call chain.
663  * @nb: The notifier_block registered to lenovo-wmi-events driver.
664  * @action: Unused.
665  * @data: The ACPI event.
666  *
667  * For LWMI_EVENT_THERMAL_MODE, set current_mode and notify platform_profile
668  * of a change.
669  *
670  * Return: notifier_block status.
671  */
lwmi_cd01_notifier_call(struct notifier_block * nb,unsigned long action,void * data)672 static int lwmi_cd01_notifier_call(struct notifier_block *nb, unsigned long action,
673 				   void *data)
674 {
675 	struct acpi_bus_event *event = data;
676 	struct lwmi_cd_priv *priv;
677 	int ret;
678 
679 	if (strcmp(event->device_class, ACPI_AC_CLASS) != 0)
680 		return NOTIFY_DONE;
681 
682 	priv = container_of(nb, struct lwmi_cd_priv, acpi_nb);
683 
684 	switch (event->type) {
685 	case ACPI_AC_NOTIFY_STATUS:
686 		ret = lwmi_cd_cache(priv);
687 		if (ret)
688 			return NOTIFY_BAD;
689 
690 		return NOTIFY_OK;
691 	default:
692 		return NOTIFY_DONE;
693 	}
694 }
695 
696 /**
697  * lwmi_cd01_unregister() - Unregister the cd01 ACPI notifier_block.
698  * @data: The ACPI event notifier_block to unregister.
699  */
lwmi_cd01_unregister(void * data)700 static void lwmi_cd01_unregister(void *data)
701 {
702 	struct notifier_block *acpi_nb = data;
703 
704 	unregister_acpi_notifier(acpi_nb);
705 }
706 
lwmi_cd_probe(struct wmi_device * wdev,const void * context)707 static int lwmi_cd_probe(struct wmi_device *wdev, const void *context)
708 {
709 	const struct lwmi_cd_info *info = context;
710 	struct lwmi_cd_priv *priv;
711 	int ret;
712 
713 	if (!info)
714 		return -EINVAL;
715 
716 	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
717 	if (!priv)
718 		return -ENOMEM;
719 
720 	priv->wdev = wdev;
721 	dev_set_drvdata(&wdev->dev, priv);
722 
723 	ret = lwmi_cd_setup(priv, info->type);
724 	if (ret)
725 		goto out;
726 
727 	switch (info->type) {
728 	case LENOVO_CAPABILITY_DATA_00: {
729 		enum lwmi_cd_type sub_component_type = LENOVO_FAN_TEST_DATA;
730 		struct capdata00 capdata00;
731 
732 		ret = lwmi_cd00_get_data(priv->list, LWMI_ATTR_ID_FAN_TEST, &capdata00);
733 		if (ret || !(capdata00.supported & LWMI_SUPP_VALID)) {
734 			dev_dbg(&wdev->dev, "capdata00 declares no fan test support\n");
735 			sub_component_type = CD_TYPE_NONE;
736 		}
737 
738 		/* Sub-master (capdata00) <-> sub-component (capdata_fan) */
739 		ret = lwmi_cd_sub_master_add(priv, sub_component_type);
740 		if (ret)
741 			goto out;
742 
743 		/* Master (lenovo-wmi-other) <-> sub-master (capdata00) */
744 		ret = component_add(&wdev->dev, &lwmi_cd_component_ops);
745 		if (ret)
746 			lwmi_cd_sub_master_del(priv);
747 
748 		goto out;
749 	}
750 	case LENOVO_CAPABILITY_DATA_01:
751 		priv->acpi_nb.notifier_call = lwmi_cd01_notifier_call;
752 
753 		ret = register_acpi_notifier(&priv->acpi_nb);
754 		if (ret)
755 			goto out;
756 
757 		ret = devm_add_action_or_reset(&wdev->dev, lwmi_cd01_unregister,
758 					       &priv->acpi_nb);
759 		if (ret)
760 			goto out;
761 
762 		ret = component_add(&wdev->dev, &lwmi_cd_component_ops);
763 		goto out;
764 	case LENOVO_FAN_TEST_DATA:
765 		ret = component_add(&wdev->dev, &lwmi_cd_sub_component_ops);
766 		goto out;
767 	default:
768 		return -EINVAL;
769 	}
770 out:
771 	if (ret) {
772 		dev_err(&wdev->dev, "failed to register %s: %d\n",
773 			info->name, ret);
774 	} else {
775 		dev_dbg(&wdev->dev, "registered %s with %u items\n",
776 			info->name, priv->list->count);
777 	}
778 	return ret;
779 }
780 
lwmi_cd_remove(struct wmi_device * wdev)781 static void lwmi_cd_remove(struct wmi_device *wdev)
782 {
783 	struct lwmi_cd_priv *priv = dev_get_drvdata(&wdev->dev);
784 
785 	switch (priv->list->type) {
786 	case LENOVO_CAPABILITY_DATA_00:
787 		lwmi_cd_sub_master_del(priv);
788 		fallthrough;
789 	case LENOVO_CAPABILITY_DATA_01:
790 		component_del(&wdev->dev, &lwmi_cd_component_ops);
791 		break;
792 	case LENOVO_FAN_TEST_DATA:
793 		component_del(&wdev->dev, &lwmi_cd_sub_component_ops);
794 		break;
795 	default:
796 		WARN_ON(1);
797 	}
798 }
799 
800 #define LWMI_CD_WDEV_ID(_type)				\
801 	.guid_string = _type##_GUID,			\
802 	.context = &lwmi_cd_table[_type],
803 
804 static const struct wmi_device_id lwmi_cd_id_table[] = {
805 	{ LWMI_CD_WDEV_ID(LENOVO_CAPABILITY_DATA_00) },
806 	{ LWMI_CD_WDEV_ID(LENOVO_CAPABILITY_DATA_01) },
807 	{ LWMI_CD_WDEV_ID(LENOVO_FAN_TEST_DATA) },
808 	{}
809 };
810 
811 static struct wmi_driver lwmi_cd_driver = {
812 	.driver = {
813 		.name = "lenovo_wmi_capdata",
814 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
815 	},
816 	.id_table = lwmi_cd_id_table,
817 	.probe = lwmi_cd_probe,
818 	.remove = lwmi_cd_remove,
819 	.no_singleton = true,
820 };
821 
822 module_wmi_driver(lwmi_cd_driver);
823 
824 MODULE_DEVICE_TABLE(wmi, lwmi_cd_id_table);
825 MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
826 MODULE_AUTHOR("Rong Zhang <i@rong.moe>");
827 MODULE_DESCRIPTION("Lenovo Capability Data WMI Driver");
828 MODULE_LICENSE("GPL");
829