2727#define pr_fmt (fmt ) KBUILD_MODNAME ": " fmt
2828
2929#include <linux/acpi.h>
30+ #include <linux/bitfield.h>
3031#include <linux/bug.h>
3132#include <linux/cleanup.h>
3233#include <linux/component.h>
5556#define ACPI_AC_CLASS "ac_adapter"
5657#define ACPI_AC_NOTIFY_STATUS 0x80
5758
59+ #define LWMI_FEATURE_ID_FAN_TEST 0x05
60+
61+ #define LWMI_ATTR_ID_FAN_TEST \
62+ (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \
63+ FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST))
64+
5865enum lwmi_cd_type {
5966 LENOVO_CAPABILITY_DATA_00 ,
6067 LENOVO_CAPABILITY_DATA_01 ,
6168 LENOVO_FAN_TEST_DATA ,
69+ CD_TYPE_NONE = -1 ,
6270};
6371
6472#define LWMI_CD_TABLE_ITEM (_type ) \
@@ -80,6 +88,20 @@ struct lwmi_cd_priv {
8088 struct notifier_block acpi_nb ; /* ACPI events */
8189 struct wmi_device * wdev ;
8290 struct cd_list * list ;
91+
92+ /*
93+ * A capdata device may be a component master of another capdata device.
94+ * E.g., lenovo-wmi-other <-> capdata00 <-> capdata_fan
95+ * |- master |- component
96+ * |- sub-master
97+ * |- sub-component
98+ */
99+ struct lwmi_cd_sub_master_priv {
100+ struct device * master_dev ;
101+ cd_list_cb_t master_cb ;
102+ struct cd_list * sub_component_list ; /* ERR_PTR(-ENODEV) implies no sub-component. */
103+ bool registered ; /* Has the sub-master been registered? */
104+ } * sub_master ;
83105};
84106
85107struct cd_list {
@@ -142,6 +164,72 @@ void lwmi_cd_match_add_all(struct device *master, struct component_match **match
142164}
143165EXPORT_SYMBOL_NS_GPL (lwmi_cd_match_add_all , "LENOVO_WMI_CAPDATA" );
144166
167+ /**
168+ * lwmi_cd_call_master_cb() - Call the master callback for the sub-component.
169+ * @priv: Pointer to the capability data private data.
170+ *
171+ * Call the master callback and pass the sub-component list to it if the
172+ * dependency chain (master <-> sub-master <-> sub-component) is complete.
173+ */
174+ static void lwmi_cd_call_master_cb (struct lwmi_cd_priv * priv )
175+ {
176+ struct cd_list * sub_component_list = priv -> sub_master -> sub_component_list ;
177+
178+ /*
179+ * Call the callback only if the dependency chain is ready:
180+ * - Binding between master and sub-master: fills master_dev and master_cb
181+ * - Binding between sub-master and sub-component: fills sub_component_list
182+ *
183+ * If a binding has been unbound before the other binding is bound, the
184+ * corresponding members filled by the former are guaranteed to be cleared.
185+ *
186+ * This function is only called in bind callbacks, and the component
187+ * framework guarantees bind/unbind callbacks may never execute
188+ * simultaneously, which implies that it's impossible to have a race
189+ * condition.
190+ *
191+ * Hence, this check is sufficient to ensure that the callback is called
192+ * at most once and with the correct state, without relying on a specific
193+ * sequence of binding establishment.
194+ */
195+ if (!sub_component_list ||
196+ !priv -> sub_master -> master_dev ||
197+ !priv -> sub_master -> master_cb )
198+ return ;
199+
200+ if (PTR_ERR (sub_component_list ) == - ENODEV )
201+ sub_component_list = NULL ;
202+ else if (WARN_ON (IS_ERR (sub_component_list )))
203+ return ;
204+
205+ priv -> sub_master -> master_cb (priv -> sub_master -> master_dev ,
206+ sub_component_list );
207+
208+ /*
209+ * Userspace may unbind a device from its driver and bind it again
210+ * through sysfs. Let's call this operation "reprobe" to distinguish it
211+ * from component "rebind".
212+ *
213+ * When reprobing capdata00/01 or the master device, the master device
214+ * is unbound from us with appropriate cleanup before we bind to it and
215+ * call master_cb. Everything is fine in this case.
216+ *
217+ * When reprobing capdata_fan, the master device has never been unbound
218+ * from us (hence no cleanup is done)[1], but we call master_cb the
219+ * second time. To solve this issue, we clear master_cb and master_dev
220+ * so we won't call master_cb twice while a binding is still complete.
221+ *
222+ * Note that we can't clear sub_component_list, otherwise reprobing
223+ * capdata01 or the master device causes master_cb to be never called
224+ * after we rebind to the master device.
225+ *
226+ * [1]: The master device does not need capdata_fan in run time, so
227+ * losing capdata_fan will not break the binding to the master device.
228+ */
229+ priv -> sub_master -> master_cb = NULL ;
230+ priv -> sub_master -> master_dev = NULL ;
231+ }
232+
145233/**
146234 * lwmi_cd_component_bind() - Bind component to master device.
147235 * @cd_dev: Pointer to the lenovo-wmi-capdata driver parent device.
@@ -152,6 +240,8 @@ EXPORT_SYMBOL_NS_GPL(lwmi_cd_match_add_all, "LENOVO_WMI_CAPDATA");
152240 * list. This is used to call lwmi_cd*_get_data to look up attribute data
153241 * from the lenovo-wmi-other driver.
154242 *
243+ * If cd_dev is a sub-master, try to call the master callback.
244+ *
155245 * Return: 0
156246 */
157247static int lwmi_cd_component_bind (struct device * cd_dev ,
@@ -163,6 +253,11 @@ static int lwmi_cd_component_bind(struct device *cd_dev,
163253 switch (priv -> list -> type ) {
164254 case LENOVO_CAPABILITY_DATA_00 :
165255 binder -> cd00_list = priv -> list ;
256+
257+ priv -> sub_master -> master_dev = om_dev ;
258+ priv -> sub_master -> master_cb = binder -> cd_fan_list_cb ;
259+ lwmi_cd_call_master_cb (priv );
260+
166261 break ;
167262 case LENOVO_CAPABILITY_DATA_01 :
168263 binder -> cd01_list = priv -> list ;
@@ -174,8 +269,168 @@ static int lwmi_cd_component_bind(struct device *cd_dev,
174269 return 0 ;
175270}
176271
272+ /**
273+ * lwmi_cd_component_unbind() - Unbind component to master device.
274+ * @cd_dev: Pointer to the lenovo-wmi-capdata driver parent device.
275+ * @om_dev: Pointer to the lenovo-wmi-other driver parent device.
276+ * @data: Unused.
277+ *
278+ * If cd_dev is a sub-master, clear the collected data from the master device to
279+ * prevent the binding establishment between the sub-master and the sub-
280+ * component (if it's about to happen) from calling the master callback.
281+ */
282+ static void lwmi_cd_component_unbind (struct device * cd_dev ,
283+ struct device * om_dev , void * data )
284+ {
285+ struct lwmi_cd_priv * priv = dev_get_drvdata (cd_dev );
286+
287+ switch (priv -> list -> type ) {
288+ case LENOVO_CAPABILITY_DATA_00 :
289+ priv -> sub_master -> master_dev = NULL ;
290+ priv -> sub_master -> master_cb = NULL ;
291+ return ;
292+ default :
293+ return ;
294+ }
295+ }
296+
177297static const struct component_ops lwmi_cd_component_ops = {
178298 .bind = lwmi_cd_component_bind ,
299+ .unbind = lwmi_cd_component_unbind ,
300+ };
301+
302+ /**
303+ * lwmi_cd_sub_master_bind() - Bind sub-component of sub-master device
304+ * @dev: The sub-master capdata basic device.
305+ *
306+ * Call component_bind_all to bind the sub-component device to the sub-master
307+ * device. On success, collect the pointer to the sub-component list and try
308+ * to call the master callback.
309+ *
310+ * Return: 0 on success, or an error code.
311+ */
312+ static int lwmi_cd_sub_master_bind (struct device * dev )
313+ {
314+ struct lwmi_cd_priv * priv = dev_get_drvdata (dev );
315+ struct cd_list * sub_component_list ;
316+ int ret ;
317+
318+ ret = component_bind_all (dev , & sub_component_list );
319+ if (ret )
320+ return ret ;
321+
322+ priv -> sub_master -> sub_component_list = sub_component_list ;
323+ lwmi_cd_call_master_cb (priv );
324+
325+ return 0 ;
326+ }
327+
328+ /**
329+ * lwmi_cd_sub_master_unbind() - Unbind sub-component of sub-master device
330+ * @dev: The sub-master capdata basic device
331+ *
332+ * Clear the collected pointer to the sub-component list to prevent the binding
333+ * establishment between the sub-master and the sub-component (if it's about to
334+ * happen) from calling the master callback. Then, call component_unbind_all to
335+ * unbind the sub-component device from the sub-master device.
336+ */
337+ static void lwmi_cd_sub_master_unbind (struct device * dev )
338+ {
339+ struct lwmi_cd_priv * priv = dev_get_drvdata (dev );
340+
341+ priv -> sub_master -> sub_component_list = NULL ;
342+
343+ component_unbind_all (dev , NULL );
344+ }
345+
346+ static const struct component_master_ops lwmi_cd_sub_master_ops = {
347+ .bind = lwmi_cd_sub_master_bind ,
348+ .unbind = lwmi_cd_sub_master_unbind ,
349+ };
350+
351+ /**
352+ * lwmi_cd_sub_master_add() - Register a sub-master with its sub-component
353+ * @priv: Pointer to the sub-master capdata device private data.
354+ * @sub_component_type: Type of the sub-component.
355+ *
356+ * Match the sub-component type and register the current capdata device as a
357+ * sub-master. If the given sub-component type is CD_TYPE_NONE, mark the sub-
358+ * component as non-existent without registering sub-master.
359+ *
360+ * Return: 0 on success, or an error code.
361+ */
362+ static int lwmi_cd_sub_master_add (struct lwmi_cd_priv * priv ,
363+ enum lwmi_cd_type sub_component_type )
364+ {
365+ struct component_match * master_match = NULL ;
366+ int ret ;
367+
368+ priv -> sub_master = devm_kzalloc (& priv -> wdev -> dev , sizeof (* priv -> sub_master ), GFP_KERNEL );
369+ if (!priv -> sub_master )
370+ return - ENOMEM ;
371+
372+ if (sub_component_type == CD_TYPE_NONE ) {
373+ /* The master callback will be called with NULL on bind. */
374+ priv -> sub_master -> sub_component_list = ERR_PTR (- ENODEV );
375+ priv -> sub_master -> registered = false;
376+ return 0 ;
377+ }
378+
379+ /*
380+ * lwmi_cd_match() needs a pointer to enum lwmi_cd_type, but on-stack
381+ * data cannot be used here. Steal one from lwmi_cd_table.
382+ */
383+ component_match_add (& priv -> wdev -> dev , & master_match , lwmi_cd_match ,
384+ (void * )& lwmi_cd_table [sub_component_type ].type );
385+ if (IS_ERR (master_match ))
386+ return PTR_ERR (master_match );
387+
388+ ret = component_master_add_with_match (& priv -> wdev -> dev , & lwmi_cd_sub_master_ops ,
389+ master_match );
390+ if (ret )
391+ return ret ;
392+
393+ priv -> sub_master -> registered = true;
394+ return 0 ;
395+ }
396+
397+ /**
398+ * lwmi_cd_sub_master_del() - Unregister a sub-master if it's registered
399+ * @priv: Pointer to the sub-master capdata device private data.
400+ */
401+ static void lwmi_cd_sub_master_del (struct lwmi_cd_priv * priv )
402+ {
403+ if (!priv -> sub_master -> registered )
404+ return ;
405+
406+ component_master_del (& priv -> wdev -> dev , & lwmi_cd_sub_master_ops );
407+ priv -> sub_master -> registered = false;
408+ }
409+
410+ /**
411+ * lwmi_cd_sub_component_bind() - Bind sub-component to sub-master device.
412+ * @sc_dev: Pointer to the sub-component capdata parent device.
413+ * @sm_dev: Pointer to the sub-master capdata parent device.
414+ * @data: Pointer used to return the capability data list pointer.
415+ *
416+ * On sub-master's bind, provide a pointer to the local capdata list.
417+ * This is used by the sub-master to call the master callback.
418+ *
419+ * Return: 0
420+ */
421+ static int lwmi_cd_sub_component_bind (struct device * sc_dev ,
422+ struct device * sm_dev , void * data )
423+ {
424+ struct lwmi_cd_priv * priv = dev_get_drvdata (sc_dev );
425+ struct cd_list * * listp = data ;
426+
427+ * listp = priv -> list ;
428+
429+ return 0 ;
430+ }
431+
432+ static const struct component_ops lwmi_cd_sub_component_ops = {
433+ .bind = lwmi_cd_sub_component_bind ,
179434};
180435
181436/*
@@ -471,9 +726,28 @@ static int lwmi_cd_probe(struct wmi_device *wdev, const void *context)
471726 goto out ;
472727
473728 switch (info -> type ) {
474- case LENOVO_CAPABILITY_DATA_00 :
729+ case LENOVO_CAPABILITY_DATA_00 : {
730+ enum lwmi_cd_type sub_component_type = LENOVO_FAN_TEST_DATA ;
731+ struct capdata00 capdata00 ;
732+
733+ ret = lwmi_cd00_get_data (priv -> list , LWMI_ATTR_ID_FAN_TEST , & capdata00 );
734+ if (ret || !(capdata00 .supported & LWMI_SUPP_VALID )) {
735+ dev_dbg (& wdev -> dev , "capdata00 declares no fan test support\n" );
736+ sub_component_type = CD_TYPE_NONE ;
737+ }
738+
739+ /* Sub-master (capdata00) <-> sub-component (capdata_fan) */
740+ ret = lwmi_cd_sub_master_add (priv , sub_component_type );
741+ if (ret )
742+ goto out ;
743+
744+ /* Master (lenovo-wmi-other) <-> sub-master (capdata00) */
475745 ret = component_add (& wdev -> dev , & lwmi_cd_component_ops );
746+ if (ret )
747+ lwmi_cd_sub_master_del (priv );
748+
476749 goto out ;
750+ }
477751 case LENOVO_CAPABILITY_DATA_01 :
478752 priv -> acpi_nb .notifier_call = lwmi_cd01_notifier_call ;
479753
@@ -489,6 +763,7 @@ static int lwmi_cd_probe(struct wmi_device *wdev, const void *context)
489763 ret = component_add (& wdev -> dev , & lwmi_cd_component_ops );
490764 goto out ;
491765 case LENOVO_FAN_TEST_DATA :
766+ ret = component_add (& wdev -> dev , & lwmi_cd_sub_component_ops );
492767 goto out ;
493768 default :
494769 return - EINVAL ;
@@ -510,10 +785,13 @@ static void lwmi_cd_remove(struct wmi_device *wdev)
510785
511786 switch (priv -> list -> type ) {
512787 case LENOVO_CAPABILITY_DATA_00 :
788+ lwmi_cd_sub_master_del (priv );
789+ fallthrough ;
513790 case LENOVO_CAPABILITY_DATA_01 :
514791 component_del (& wdev -> dev , & lwmi_cd_component_ops );
515792 break ;
516793 case LENOVO_FAN_TEST_DATA :
794+ component_del (& wdev -> dev , & lwmi_cd_sub_component_ops );
517795 break ;
518796 default :
519797 WARN_ON (1 );
0 commit comments