mirror of
https://github.com/ps5-linux/ps5-linux-mwifiex.git
synced 2026-10-18 21:09:47 -05:00
* Stop a firmware lockup from deadlocking the whole system A wedged IW620 firmware used to freeze the entire machine, not just wifi. woal_cfg80211_dump_station_info() runs while cfg80211 holds the wiphy mutex and nl80211_pre_doit() holds RTNL. MOAL_IOCTL_WAIT has no timeout, so once the command queue wedged NetworkManager blocked there forever, RTNL stayed held, and every network-touching syscall on the box blocked in D state -- no desktop icons, nothing responsive, hard power-off the only way out: NetworkManager (S) woal_wait_ioctl_complete [moal] <- holds WIPHY mutex wpa_supplicant (D) nl80211_pre_doit -> mutex_lock <- holds RTNL geoclue (D) rtnl_dumpit -> rtnl_lock <- waits RTNL Two independent causes, so two patches. 1. The command queue wedged. On a timeout the driver only released curr_cmd for a small whitelist of commands; anything else (MAC_MULTICAST_ADR, in the observed failure) left curr_cmd set and cmd_sent MTRUE, so every later ioctl queued behind a command that would never be sent. Releasing the command and completing its ioctl now happens on every timeout; the whitelist only chooses between carrying on and declaring a hang. The retry cap gets its own soft_cmd_timeout counter, cleared whenever a response arrives so it really counts consecutive timeouts. It cannot reuse num_cmd_timeout: wlan_process_cmdresp() discards every command response while that is non-zero, so it must keep being cleared after a recovery. 2. The wait was unbounded. The four firmware round-trips in woal_cfg80211_dump_station_info() (signal, stats, bss_info, dtim_period) now use MOAL_IOCTL_WAIT_TIMEOUT, capping each at 20s so a dead firmware can no longer strand RTNL. That function backs both .get_station and .dump_station. Also in install.sh: - Reset the driver tree to a pristine $REF before patching. Without it a tree left from a previous run still carries the old version of a patch, which then matches neither the apply nor the reverse-apply check, and the run dies with "does not apply cleanly". - Switch the default tuning from ps_mode=0 auto_ds=0 amsdu_disable=0 to 2 2 1, verified on a cold boot on 7.1.3-hdmifix with this patch stack. This also matches the linux-ps5 package's moal.conf, which previously disagreed -- and since ps5-iw620.conf sorts after moal.conf, the value written here silently wins. - Add FW_RESET_OPTIONS for opting into firmware auto-reset. Off by default: woal_request_fw_reload() rejects every mode with -EINVAL unless the low byte of indrstcfg is 1 or 2 (module default 0xffffffff), so auto_fw_reload alone is a no-op, and neither is tested on PS5 hardware. Verified: patches apply cleanly to a pristine lf-6.18.2_1.0.0 checkout in install.sh order and build without warnings; a cold boot onto the result downloads firmware, associates, and runs clean. The lockup is sporadic, so the recovery paths themselves are not yet exercised in the field. Assisted-by: Claude <noreply@anthropic.com> * Explain in the generated modprobe config that it overrides moal.conf install.sh writes /etc/modprobe.d/ps5-iw620.conf, and the linux-ps5 package ships /etc/modprobe.d/moal.conf. Both set "options moal", and modprobe concatenates those lines across every *.conf rather than letting one file replace another, so the module receives the whole list twice and a repeated scalar resolves to the last one read. ps5-iw620.conf sorts after moal.conf, so it silently wins and edits to moal.conf appear to do nothing. Nothing functional changes; the generated options line is byte-identical. The header just makes the precedence discoverable from the file itself, which a hand-added comment could not do because the next run overwrites it. Assisted-by: Claude <noreply@anthropic.com> * changes for 7.2.y: add separate patch file --------- Co-authored-by: Nikolai Shcheglov <ndnd@mail.ru>
53 lines
2.4 KiB
Diff
53 lines
2.4 KiB
Diff
diff --git a/mlinux/moal_sta_cfg80211.c b/mlinux/moal_sta_cfg80211.c
|
|
index 05e820f..0d5942c 100644
|
|
--- a/mlinux/moal_sta_cfg80211.c
|
|
+++ b/mlinux/moal_sta_cfg80211.c
|
|
@@ -4675,10 +4675,17 @@ static mlan_status woal_cfg80211_dump_station_info(moal_private *priv,
|
|
sinfo->filled |= MBIT64(NL80211_STA_INFO_FCS_ERROR_COUNT);
|
|
#endif
|
|
|
|
+ /* Every firmware round-trip below runs while cfg80211 holds the wiphy
|
|
+ * mutex, and nl80211_pre_doit() takes RTNL before that. MOAL_IOCTL_WAIT
|
|
+ * has no timeout, so a firmware that stops answering strands RTNL and
|
|
+ * every network-touching syscall on the machine blocks in D state.
|
|
+ * MOAL_IOCTL_WAIT_TIMEOUT bounds each one at MOAL_IOCTL_TIMEOUT (20s).
|
|
+ */
|
|
+
|
|
/* Get signal information from the firmware */
|
|
memset(&signal, 0, sizeof(mlan_ds_get_signal));
|
|
if (MLAN_STATUS_SUCCESS !=
|
|
- woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
|
|
+ woal_get_signal_info(priv, MOAL_IOCTL_WAIT_TIMEOUT, &signal)) {
|
|
PRINTM(MERROR, "Error getting signal information\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
@@ -4687,7 +4694,7 @@ static mlan_status woal_cfg80211_dump_station_info(moal_private *priv,
|
|
/* Get stats information from the firmware */
|
|
memset(&stats, 0, sizeof(mlan_ds_get_stats));
|
|
if (MLAN_STATUS_SUCCESS !=
|
|
- woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
|
|
+ woal_get_stats_info(priv, MOAL_IOCTL_WAIT_TIMEOUT, &stats)) {
|
|
PRINTM(MERROR, "Error getting stats information\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
@@ -4717,7 +4724,7 @@ static mlan_status woal_cfg80211_dump_station_info(moal_private *priv,
|
|
sinfo->filled |= STATION_INFO_BSS_PARAM;
|
|
#endif
|
|
sinfo->bss_param.flags = 0;
|
|
- ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
|
|
+ ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT_TIMEOUT, &bss_info);
|
|
if (ret)
|
|
goto done;
|
|
if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_PREAMBLE)
|
|
@@ -4726,8 +4733,8 @@ static mlan_status woal_cfg80211_dump_station_info(moal_private *priv,
|
|
sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
|
|
sinfo->bss_param.beacon_interval = bss_info.beacon_interval;
|
|
/* Get DTIM period */
|
|
- ret = woal_set_get_dtim_period(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
|
|
- &dtim_period);
|
|
+ ret = woal_set_get_dtim_period(priv, MLAN_ACT_GET,
|
|
+ MOAL_IOCTL_WAIT_TIMEOUT, &dtim_period);
|
|
if (ret) {
|
|
PRINTM(MERROR, "Get DTIM period failed\n");
|
|
goto done;
|