Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kitakar5525/490e756a037d3b848a9fa275bab350fa to your computer and use it in GitHub Desktop.
Save kitakar5525/490e756a037d3b848a9fa275bab350fa to your computer and use it in GitHub Desktop.
Ported to Linux 4.19 to try to fix wifi function level reset for Surface series Marvell-8897, but not working.
From fcf98b6c33ada1d0b68b2f27ba439539fdb52afa Mon Sep 17 00:00:00 2001
From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
Date: Sat, 21 Dec 2019 10:51:49 +0900
Subject: [PATCH 1/3] CHROMIUM: PCI: Add double-reset quirk for Marvell 8997
Marvell 8997 PCIe modules may not reinitialize correctly if we only
reset (FLR) once. To work properly, we need to perform one FLR,
reinitialize the device, then perform another FLR. We only have a rough
explanation from the vendor as to why this is necessary, but the essence
seems to be that firmware init after a single FLR doesn't configure
something quite the same as if we perform a second FLR.
This approach works by implementing a callback for
pci_dev_specific_reset() that matches the 8997 device ID under both
Marvell vendor IDs. This reset method performs two resets, restoring the
driver in between.
Technically, this could probably be fixed with an updated firmware, but
the vendor has been MIA for >8 months, so we're not hopeful.
BUG=b:64074778
TEST=`test_that ... network_WiFi_Reset` on Kevin
TEST=C=0 ; while : ; do
echo "C=$C $(date)"
let C+=1
echo 1 > /sys/kernel/debug/mwifiex/mlan0/reset
rmmod mwifiex_pcie
sleep 6
modprobe mwifiex_pcie
sleep 3
done
Change-Id: I0adeb973a69a6f9daa0f22d63dd076ceb15af66f
Signed-off-by: Brian Norris <briannorris@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1010919
Reviewed-by: Dmitry Torokhov <dtor@chromium.org>
From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
Ported to 4.19
---
drivers/pci/pci.c | 4 ++--
drivers/pci/pci.h | 4 ++++
drivers/pci/quirks.c | 39 +++++++++++++++++++++++++++++++++++++++
3 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c9f51fc24563..abcd480fb40b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4662,7 +4662,7 @@ static void pci_dev_unlock(struct pci_dev *dev)
pci_cfg_access_unlock(dev);
}
-static void pci_dev_save_and_disable(struct pci_dev *dev)
+void pci_dev_save_and_disable(struct pci_dev *dev)
{
const struct pci_error_handlers *err_handler =
dev->driver ? dev->driver->err_handler : NULL;
@@ -4693,7 +4693,7 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)
pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
}
-static void pci_dev_restore(struct pci_dev *dev)
+void pci_dev_restore(struct pci_dev *dev)
{
const struct pci_error_handlers *err_handler =
dev->driver ? dev->driver->err_handler : NULL;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index e9ede82ee2c2..288ac57a5ff4 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -538,4 +538,8 @@ static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
static inline void pci_aer_clear_device_status(struct pci_dev *dev) { }
#endif
+int pcie_flr(struct pci_dev *dev);
+void pci_dev_restore(struct pci_dev *dev);
+void pci_dev_save_and_disable(struct pci_dev *dev);
+
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 64933994f772..4a7085058cdb 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3699,6 +3699,8 @@ static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
#define PCI_DEVICE_ID_INTEL_IVB_M_VGA 0x0156
#define PCI_DEVICE_ID_INTEL_IVB_M2_VGA 0x0166
+#define PCIE_DEVICE_ID_MARVELL_88W8997 0x2b42
+
/*
* The Samsung SM961/PM961 controller can sometimes enter a fatal state after
* FLR where config space reads from the device return -1. We seem to be
@@ -3801,6 +3803,39 @@ static int delay_250ms_after_flr(struct pci_dev *dev, int probe)
return 0;
}
+/*
+ * Some Marvell Wifi devices may utilize FLR for reset/recovery when their
+ * firmware crashes. However, Marvell firmware can have trouble reinitializing
+ * the device correctly after just a single reset, so we instead perform 2
+ * resets, allowing the driver to reinitialize the driver in between.
+ *
+ * Lifted partially from pci_reset_function(), but done entirely under
+ * pci_dev_lock().
+ */
+static int reset_marvell_wifi_double_flr(struct pci_dev *dev, int probe)
+{
+ int ret;
+
+ if (probe)
+ return pcie_flr(dev);
+
+ /* Perform first reset. */
+ ret = pcie_flr(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Notify and restore any driver in between resets, to give it a chance
+ * to reload firmware. Without this, the device may not come up
+ * completely correctly.
+ */
+ pci_dev_restore(dev);
+ pci_dev_save_and_disable(dev);
+
+ /* Perform second reset. */
+ return pcie_flr(dev);
+}
+
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
reset_intel_82599_sfp_virtfn },
@@ -3812,6 +3847,10 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
{ PCI_VENDOR_ID_INTEL, 0x0953, delay_250ms_after_flr },
{ PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
reset_chelsio_generic_dev },
+ { PCI_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8997,
+ reset_marvell_wifi_double_flr },
+ { PCI_VENDOR_ID_MARVELL_EXT, PCIE_DEVICE_ID_MARVELL_88W8997,
+ reset_marvell_wifi_double_flr },
{ 0 }
};
--
2.24.1
From 7357711ee9ba85b810818cb50c34bc6c28d010e6 Mon Sep 17 00:00:00 2001
From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
Date: Sun, 22 Dec 2019 07:01:16 +0900
Subject: [PATCH 2/3] PCI: double-reset quirk: add Marvell-8897
---
drivers/pci/quirks.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 4a7085058cdb..5e3bdbefae51 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3700,6 +3700,7 @@ static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
#define PCI_DEVICE_ID_INTEL_IVB_M2_VGA 0x0166
#define PCIE_DEVICE_ID_MARVELL_88W8997 0x2b42
+#define PCIE_DEVICE_ID_MARVELL_88W8897 0x2b38
/*
* The Samsung SM961/PM961 controller can sometimes enter a fatal state after
@@ -3851,6 +3852,10 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
reset_marvell_wifi_double_flr },
{ PCI_VENDOR_ID_MARVELL_EXT, PCIE_DEVICE_ID_MARVELL_88W8997,
reset_marvell_wifi_double_flr },
+ { PCI_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897,
+ reset_marvell_wifi_double_flr },
+ { PCI_VENDOR_ID_MARVELL_EXT, PCIE_DEVICE_ID_MARVELL_88W8897,
+ reset_marvell_wifi_double_flr },
{ 0 }
};
--
2.24.1
From 8b73e3accf6dee4e6ecac0d9421c5a191fb5662d Mon Sep 17 00:00:00 2001
From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
Date: Sun, 22 Dec 2019 07:32:59 +0900
Subject: [PATCH 3/3] PCI: double-reset quirk: add debug output
---
drivers/pci/quirks.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5e3bdbefae51..809af759af11 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3817,10 +3817,14 @@ static int reset_marvell_wifi_double_flr(struct pci_dev *dev, int probe)
{
int ret;
+ pci_alert(dev, "DEBUG: %s: called\n",__FUNCTION__);
+ pci_alert(dev, "DEBUG: using double-reset quirk for resseting marvell pcie wifi card\n");
+
if (probe)
return pcie_flr(dev);
/* Perform first reset. */
+ pci_alert(dev, "DEBUG: performing first reset...\n");
ret = pcie_flr(dev);
if (ret)
return ret;
@@ -3834,6 +3838,7 @@ static int reset_marvell_wifi_double_flr(struct pci_dev *dev, int probe)
pci_dev_save_and_disable(dev);
/* Perform second reset. */
+ pci_alert(dev, "DEBUG: performing second reset...\n");
return pcie_flr(dev);
}
--
2.24.1
dmesg log on Surface Book 1.
Result is the same as not using this quirk.
$ dmesg -xw
kern :notice: [ 0.000000] Linux version 4.19.90 (ubuntu@ip-172-31-25-89) (Chromium OS 10.0_pre370808_p20191029-r6 clang version 10.0.0 (/var/cache/chromeos-cache/distfiles/host/egit-src/llvm-project 1bea97c971d60f261f1bdfaa7b6d9cb30a6962fd) (based on LLVM 10.0.0svn)) #7 SMP PREEMPT Sun Dec 22 07:35:39 JST 2019
kern :info : [ 0.000000] Command line: BOOT_IMAGE=/syslinux/vmlinuz.A init=/sbin/init boot=local rootwait ro noresume noswap loglevel=7 noinitrd console= i915.modeset=1 cros_efi cros_debug root=PARTUUID=580596c5-d3fe-4fe4-98b5-3bc8df601d10 nvme_core.default_ps_max_latency_us=200000
[...]
#
# card reset:
# echo 1 | sudo tee /sys/kernel/debug/mwifiex/mlan0/reset
#
kern :info : [ 104.438758] mwifiex_pcie 0000:03:00.0: Resetting per request
kern :info : [ 104.441392] mwifiex_pcie 0000:03:00.0: info: successfully disconnected from [BSSID]: reason code 3
kern :info : [ 104.442383] mwifiex_pcie 0000:03:00.0: info: shutdown mwifiex...
kern :info : [ 104.442575] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 104.442578] mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed
kern :info : [ 104.442580] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 104.442581] mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed
kern :info : [ 104.442582] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 104.442583] mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed
kern :info : [ 104.442584] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 104.442585] mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed
kern :info : [ 104.442586] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 104.442587] mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed
kern :info : [ 104.442588] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 104.453396] mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed
kern :info : [ 104.453405] mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed
kern :alert : [ 104.468537] mwifiex_pcie 0000:03:00.0: DEBUG: reset_marvell_wifi_double_flr: called
kern :alert : [ 104.468540] mwifiex_pcie 0000:03:00.0: DEBUG: using double-reset quirk for resseting marvell pcie wifi card
kern :alert : [ 104.468542] mwifiex_pcie 0000:03:00.0: DEBUG: performing first reset...
kern :info : [ 104.582215] mwifiex_pcie 0000:03:00.0: WLAN FW already running! Skip FW dnld
kern :info : [ 104.582218] mwifiex_pcie 0000:03:00.0: WLAN FW is active
kern :info : [ 104.591206] arc_mlan0: port 1(veth_mlan0) entered disabled state
kern :info : [ 104.594265] device veth_mlan0 left promiscuous mode
kern :info : [ 104.594270] arc_mlan0: port 1(veth_mlan0) entered disabled state
kern :info : [ 104.627226] mwifiex_pcie 0000:03:00.0: Unknown api_id: 4
kern :info : [ 104.673677] mwifiex_pcie 0000:03:00.0: info: MWIFIEX VERSION: mwifiex 1.0 (15.68.19.p21)
kern :info : [ 104.673681] mwifiex_pcie 0000:03:00.0: driver_version = mwifiex 1.0 (15.68.19.p21)
kern :info : [ 104.674124] mwifiex_pcie 0000:03:00.0: info: shutdown mwifiex...
kern :info : [ 104.678306] mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed
kern :alert : [ 104.690539] mwifiex_pcie 0000:03:00.0: DEBUG: performing second reset...
kern :info : [ 104.802873] mwifiex_pcie 0000:03:00.0: WLAN FW already running! Skip FW dnld
kern :info : [ 104.802877] mwifiex_pcie 0000:03:00.0: WLAN FW is active
kern :info : [ 104.861120] mwifiex_pcie 0000:03:00.0: Unknown api_id: 4
kern :info : [ 104.885085] mwifiex_pcie 0000:03:00.0: info: MWIFIEX VERSION: mwifiex 1.0 (15.68.19.p21)
kern :info : [ 104.885088] mwifiex_pcie 0000:03:00.0: driver_version = mwifiex 1.0 (15.68.19.p21)
kern :info : [ 104.907688] IPv6: ADDRCONF(NETDEV_UP): mlan0: link is not ready
kern :info : [ 104.963710] IPv6: ADDRCONF(NETDEV_UP): veth_mlan0: link is not ready
kern :info : [ 104.970196] arc_mlan0: port 1(veth_mlan0) entered blocking state
kern :info : [ 104.970199] arc_mlan0: port 1(veth_mlan0) entered disabled state
kern :info : [ 104.970302] device veth_mlan0 entered promiscuous mode
kern :info : [ 104.970358] arc_mlan0: port 1(veth_mlan0) entered blocking state
kern :info : [ 104.970359] arc_mlan0: port 1(veth_mlan0) entered forwarding state
kern :info : [ 104.988955] mlan0: renamed from peer_mlan0
kern :info : [ 104.998881] IPv6: ADDRCONF(NETDEV_CHANGE): veth_mlan0: link becomes ready
kern :info : [ 107.931286] mwifiex_pcie 0000:03:00.0: info: trying to associate to '[SSID]' bssid [BSSID]
kern :info : [ 108.012236] mwifiex_pcie 0000:03:00.0: info: associated to bssid [BSSID] successfully
kern :info : [ 130.207236] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 140.163589] mwifiex_pcie 0000:03:00.0: info: successfully disconnected from [BSSID]: reason code 15
kern :info : [ 142.495220] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 142.495233] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 154.783288] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 154.783300] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 167.071286] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 167.071299] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 179.359300] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 179.359312] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 191.647198] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 191.647204] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 203.935218] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 203.935231] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 216.223264] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 216.223276] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 228.511256] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 228.511267] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 240.799267] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 240.799274] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 253.087276] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 253.087289] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 265.376285] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 265.376298] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
kern :info : [ 277.663327] mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110
kern :info : [ 277.663339] mwifiex_pcie 0000:03:00.0: deleting the crypto keys
#
# no more output from mwifiex_pcie
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment