Skip to content

Commit

Permalink
mwifiex: Add quirk resetting the PCI bridge on Surface Pro 5 devices
Browse files Browse the repository at this point in the history
The most recent firmware of the 88W8897 card reports a hardcoded LTR
value to the system during initialization (probably as an (unsuccessful)
attempt of the developers to fix firmware crashes). This LTR value
prevents certain systems like the Microsoft Surface Pro 5 from entering
deep powersaving states (platform C-State 10), because the exit latency
of that state would be higher than what the card can tolerate.

Now the card works just the same (including the firmware crashes) when
that hardcoded LTR value is reported, so it's kind of useless and only
prevents us from saving power.

It appears that the power management core of the PCH resets its stored
LTR values when doing a function level reset of the PCI bridge device.
ALso the card firmware won't report a new LTR unless it's restarted, so
resetting the bridge device seems to be a good solution for resetting
the LTR value to 0 and thus allowing deep powersaving states.
  • Loading branch information
jonas2515 committed Nov 12, 2020
1 parent e8470c7 commit b5fbb78
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 2 deletions.
12 changes: 12 additions & 0 deletions drivers/net/wireless/marvell/mwifiex/pcie.c
Original file line number Diff line number Diff line change
Expand Up @@ -1600,9 +1600,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
struct pci_dev *pdev = card->dev;
struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask;

/* Trigger a function level reset of the PCI bridge device, this makes
* the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value
* that prevents the system from entering package C10 and S0ix powersaving
* states.
* We need to do it here because it must happen after firmware
* initialization and this function is called after that is done.
*/
if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE)
pci_reset_function(parent_pdev);

/* Write the RX ring read pointer in to reg->rx_rdptr */
if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
tx_wrap)) {
Expand Down
8 changes: 6 additions & 2 deletions drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
QUIRK_NO_BRIDGE_D3),
QUIRK_NO_BRIDGE_D3 |
QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Pro 5 (LTE)",
Expand All @@ -53,7 +54,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"),
},
.driver_data = (void *)(QUIRK_FW_RST_D3COLD |
QUIRK_NO_BRIDGE_D3),
QUIRK_NO_BRIDGE_D3 |
QUIRK_DO_FLR_ON_BRIDGE),
},
{
.ident = "Surface Pro 6",
Expand Down Expand Up @@ -147,6 +149,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card)
if (card->quirks & QUIRK_NO_BRIDGE_D3)
dev_info(&pdev->dev,
"quirk no_brigde_d3 enabled\n");
if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE)
dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n");
}

static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
#define QUIRK_FW_RST_WSID_S3 BIT(1)
#define QUIRK_NO_BRIDGE_D3 BIT(2)
#define QUIRK_DO_FLR_ON_BRIDGE BIT(4)

void mwifiex_initialize_quirks(struct pcie_service_card *card);
int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev);
Expand Down

0 comments on commit b5fbb78

Please sign in to comment.