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 {