ideapad-laptop incorrectly sets RF-kill block on initialization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I have found an issue in the ideapad-laptop driver which causes WiFi
to not work on the Lenovo Legion Y720 laptop. It seems the issue is
generally present on this laptop as can be found by googling and
finding that the workaround is to blacklist ideapad-laptop.

In the code comment here:
https://github.com/torvalds/linux/blob/1df27313f50a57497c1faeb6a6ae4ca939c85a7d/drivers/platform/x86/ideapad-laptop.c#L1462
it is explained that the driver has a list of devices which are known
to have an RF-kill switch and for other devices it assumes that it
does not have one. Since the list is in fact empty, one would conclude
that the driver should never cause an RF-kill block. However on this
laptop loading the driver has this exact effect.

The reason is what seems to be a bug here:
https://github.com/torvalds/linux/blob/1df27313f50a57497c1faeb6a6ae4ca939c85a7d/drivers/platform/x86/ideapad-laptop.c#L1001
At initialization, ideapad_register_rfkill() sets the initial RF-kill
block state based on reading the state of the possibly nonexisting
RF-kill switch without considering priv->features.hw_rfkill_switch.
This is inconsistent with ideapad_sync_rfk_state() which sets
unblocked if hw_rfkill_switch is false. The result is that
ideapad_register_rfkill() would block but ideapad_sync_rfk_state()
would unblock as soon as it is called. But on my laptop
ideapad_sync_rfk_state() is presumably never called and the blocked
state persists indefinitely. I have verified this by changing
ideapad_register_rfkill() to use the same logic as
ideapad_sync_rfk_state() which has fixed the problem.

I am attaching a patch for master and 5.4, I have only tested the latter.
--- a/drivers/platform/x86/ideapad-laptop.c	2021-03-17 21:27:39.098544023 +0100
+++ b/drivers/platform/x86/ideapad-laptop.c	2021-03-17 21:28:59.059343028 +0100
@@ -998,9 +998,13 @@
 	if (!priv->rfk[dev])
 		return -ENOMEM;
 
-	err = read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode - 1, &rf_enabled);
-	if (err)
+	if (!priv->features.hw_rfkill_switch) {
 		rf_enabled = 1;
+	} else {
+		err = read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode - 1, &rf_enabled);
+		if (err)
+			rf_enabled = 1;
+	}
 
 	rfkill_init_sw_state(priv->rfk[dev], !rf_enabled);
 
diff -urN linux-5.4.104.orig/drivers/platform/x86/ideapad-laptop.c linux-5.4.104/drivers/platform/x86/ideapad-laptop.c
--- linux-5.4.104.orig/drivers/platform/x86/ideapad-laptop.c	2021-03-16 19:02:12.126383099 +0100
+++ linux-5.4.104/drivers/platform/x86/ideapad-laptop.c	2021-03-16 19:07:04.380961129 +0100
@@ -616,7 +616,8 @@
 	if (!priv->rfk[dev])
 		return -ENOMEM;
 
-	if (read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode-1,
+	if (!priv->has_hw_rfkill_switch ||
+            read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode-1,
 			 &sw_blocked)) {
 		rfkill_init_sw_state(priv->rfk[dev], 0);
 	} else {

[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux