1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/dmi.h>
19
20#include "pcie_quirks.h"
21
22
23static const struct dmi_system_id mwifiex_quirk_table[] = {
24 {
25 .ident = "Surface Pro 4",
26 .matches = {
27 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
28 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"),
29 },
30 .driver_data = (void *)QUIRK_FW_RST_D3COLD,
31 },
32 {
33 .ident = "Surface Pro 5",
34 .matches = {
35
36 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
37 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"),
38 },
39 .driver_data = (void *)QUIRK_FW_RST_D3COLD,
40 },
41 {
42 .ident = "Surface Pro 5 (LTE)",
43 .matches = {
44
45 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
46 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"),
47 },
48 .driver_data = (void *)QUIRK_FW_RST_D3COLD,
49 },
50 {
51 .ident = "Surface Pro 6",
52 .matches = {
53 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
54 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"),
55 },
56 .driver_data = (void *)QUIRK_FW_RST_D3COLD,
57 },
58 {
59 .ident = "Surface Book 1",
60 .matches = {
61 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
62 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"),
63 },
64 .driver_data = (void *)QUIRK_FW_RST_D3COLD,
65 },
66 {
67 .ident = "Surface Book 2",
68 .matches = {
69 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
70 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"),
71 },
72 .driver_data = (void *)QUIRK_FW_RST_D3COLD,
73 },
74 {
75 .ident = "Surface Laptop 1",
76 .matches = {
77 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
78 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"),
79 },
80 .driver_data = (void *)QUIRK_FW_RST_D3COLD,
81 },
82 {
83 .ident = "Surface Laptop 2",
84 .matches = {
85 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
86 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"),
87 },
88 .driver_data = (void *)QUIRK_FW_RST_D3COLD,
89 },
90 {}
91};
92
93void mwifiex_initialize_quirks(struct pcie_service_card *card)
94{
95 struct pci_dev *pdev = card->dev;
96 const struct dmi_system_id *dmi_id;
97
98 dmi_id = dmi_first_match(mwifiex_quirk_table);
99 if (dmi_id)
100 card->quirks = (uintptr_t)dmi_id->driver_data;
101
102 if (!card->quirks)
103 dev_info(&pdev->dev, "no quirks enabled\n");
104 if (card->quirks & QUIRK_FW_RST_D3COLD)
105 dev_info(&pdev->dev, "quirk reset_d3cold enabled\n");
106}
107
108static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)
109{
110 dev_info(&pdev->dev, "putting into D3cold...\n");
111
112 pci_save_state(pdev);
113 if (pci_is_enabled(pdev))
114 pci_disable_device(pdev);
115 pci_set_power_state(pdev, PCI_D3cold);
116}
117
118static int mwifiex_pcie_set_power_d0(struct pci_dev *pdev)
119{
120 int ret;
121
122 dev_info(&pdev->dev, "putting into D0...\n");
123
124 pci_set_power_state(pdev, PCI_D0);
125 ret = pci_enable_device(pdev);
126 if (ret) {
127 dev_err(&pdev->dev, "pci_enable_device failed\n");
128 return ret;
129 }
130 pci_restore_state(pdev);
131
132 return 0;
133}
134
135int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev)
136{
137 struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
138 int ret;
139
140
141 dev_info(&pdev->dev, "Using reset_d3cold quirk to perform FW reset\n");
142
143
144
145
146
147
148
149
150 mwifiex_pcie_set_power_d3cold(pdev);
151 mwifiex_pcie_set_power_d3cold(parent_pdev);
152
153 ret = mwifiex_pcie_set_power_d0(parent_pdev);
154 if (ret)
155 return ret;
156 ret = mwifiex_pcie_set_power_d0(pdev);
157 if (ret)
158 return ret;
159
160 return 0;
161}
162