Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // NXP Wireless LAN device driver: PCIE and platform specific quirks
0003 
0004 #include <linux/dmi.h>
0005 
0006 #include "pcie_quirks.h"
0007 
0008 /* quirk table based on DMI matching */
0009 static const struct dmi_system_id mwifiex_quirk_table[] = {
0010     {
0011         .ident = "Surface Pro 4",
0012         .matches = {
0013             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0014             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"),
0015         },
0016         .driver_data = (void *)QUIRK_FW_RST_D3COLD,
0017     },
0018     {
0019         .ident = "Surface Pro 5",
0020         .matches = {
0021             /* match for SKU here due to generic product name "Surface Pro" */
0022             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0023             DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"),
0024         },
0025         .driver_data = (void *)QUIRK_FW_RST_D3COLD,
0026     },
0027     {
0028         .ident = "Surface Pro 5 (LTE)",
0029         .matches = {
0030             /* match for SKU here due to generic product name "Surface Pro" */
0031             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0032             DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"),
0033         },
0034         .driver_data = (void *)QUIRK_FW_RST_D3COLD,
0035     },
0036     {
0037         .ident = "Surface Pro 6",
0038         .matches = {
0039             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0040             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"),
0041         },
0042         .driver_data = (void *)QUIRK_FW_RST_D3COLD,
0043     },
0044     {
0045         .ident = "Surface Book 1",
0046         .matches = {
0047             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0048             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"),
0049         },
0050         .driver_data = (void *)QUIRK_FW_RST_D3COLD,
0051     },
0052     {
0053         .ident = "Surface Book 2",
0054         .matches = {
0055             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0056             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"),
0057         },
0058         .driver_data = (void *)QUIRK_FW_RST_D3COLD,
0059     },
0060     {
0061         .ident = "Surface Laptop 1",
0062         .matches = {
0063             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0064             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"),
0065         },
0066         .driver_data = (void *)QUIRK_FW_RST_D3COLD,
0067     },
0068     {
0069         .ident = "Surface Laptop 2",
0070         .matches = {
0071             DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0072             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"),
0073         },
0074         .driver_data = (void *)QUIRK_FW_RST_D3COLD,
0075     },
0076     {}
0077 };
0078 
0079 void mwifiex_initialize_quirks(struct pcie_service_card *card)
0080 {
0081     struct pci_dev *pdev = card->dev;
0082     const struct dmi_system_id *dmi_id;
0083 
0084     dmi_id = dmi_first_match(mwifiex_quirk_table);
0085     if (dmi_id)
0086         card->quirks = (uintptr_t)dmi_id->driver_data;
0087 
0088     if (!card->quirks)
0089         dev_info(&pdev->dev, "no quirks enabled\n");
0090     if (card->quirks & QUIRK_FW_RST_D3COLD)
0091         dev_info(&pdev->dev, "quirk reset_d3cold enabled\n");
0092 }
0093 
0094 static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)
0095 {
0096     dev_info(&pdev->dev, "putting into D3cold...\n");
0097 
0098     pci_save_state(pdev);
0099     if (pci_is_enabled(pdev))
0100         pci_disable_device(pdev);
0101     pci_set_power_state(pdev, PCI_D3cold);
0102 }
0103 
0104 static int mwifiex_pcie_set_power_d0(struct pci_dev *pdev)
0105 {
0106     int ret;
0107 
0108     dev_info(&pdev->dev, "putting into D0...\n");
0109 
0110     pci_set_power_state(pdev, PCI_D0);
0111     ret = pci_enable_device(pdev);
0112     if (ret) {
0113         dev_err(&pdev->dev, "pci_enable_device failed\n");
0114         return ret;
0115     }
0116     pci_restore_state(pdev);
0117 
0118     return 0;
0119 }
0120 
0121 int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev)
0122 {
0123     struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
0124     int ret;
0125 
0126     /* Power-cycle (put into D3cold then D0) */
0127     dev_info(&pdev->dev, "Using reset_d3cold quirk to perform FW reset\n");
0128 
0129     /* We need to perform power-cycle also for bridge of wifi because
0130      * on some devices (e.g. Surface Book 1), the OS for some reasons
0131      * can't know the real power state of the bridge.
0132      * When tried to power-cycle only wifi, the reset failed with the
0133      * following dmesg log:
0134      * "Cannot transition to power state D0 for parent in D3hot".
0135      */
0136     mwifiex_pcie_set_power_d3cold(pdev);
0137     mwifiex_pcie_set_power_d3cold(parent_pdev);
0138 
0139     ret = mwifiex_pcie_set_power_d0(parent_pdev);
0140     if (ret)
0141         return ret;
0142     ret = mwifiex_pcie_set_power_d0(pdev);
0143     if (ret)
0144         return ret;
0145 
0146     return 0;
0147 }