]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/net/wireless/ath/wil6210/pcie_bus.c
wil6210: fix for memory corruption upon rmmod
[mirror_ubuntu-bionic-kernel.git] / drivers / net / wireless / ath / wil6210 / pcie_bus.c
CommitLineData
2be7d22f 1/*
02525a79 2 * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
2be7d22f
VK
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
2be7d22f 17#include <linux/module.h>
2be7d22f
VK
18#include <linux/pci.h>
19#include <linux/moduleparam.h>
20
21#include "wil6210.h"
22
23static int use_msi = 1;
24module_param(use_msi, int, S_IRUGO);
25MODULE_PARM_DESC(use_msi,
26 " Use MSI interrupt: "
27 "0 - don't, 1 - (default) - single, or 3");
28
94b7b64c
VK
29static bool debug_fw; /* = false; */
30module_param(debug_fw, bool, S_IRUGO);
31MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
32
2be7d22f
VK
33/* Bus ops */
34static int wil_if_pcie_enable(struct wil6210_priv *wil)
35{
36 struct pci_dev *pdev = wil->pdev;
37 int rc;
2bdc0700
VK
38 /* on platforms with buggy ACPI, pdev->msi_enabled may be set to
39 * allow pci_enable_device to work. This indicates INTx was not routed
40 * and only MSI should be used
41 */
42 int msi_only = pdev->msi_enabled;
43
9cf10d62
VK
44 wil_dbg_misc(wil, "%s()\n", __func__);
45
2bdc0700 46 pdev->msi_enabled = 0;
2be7d22f
VK
47
48 pci_set_master(pdev);
49
50 /*
51 * how many MSI interrupts to request?
52 */
53 switch (use_msi) {
54 case 3:
55 case 1:
b4b39061
AG
56 wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi);
57 break;
2be7d22f 58 case 0:
b4b39061 59 wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
2be7d22f
VK
60 break;
61 default:
b4b39061 62 wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi);
2be7d22f
VK
63 use_msi = 1;
64 }
b4b39061
AG
65
66 if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) {
67 wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
68 use_msi = 1;
69 }
70
71 if (use_msi == 1 && pci_enable_msi(pdev)) {
72 wil_err(wil, "pci_enable_msi failed, use INTx\n");
73 use_msi = 0;
2be7d22f
VK
74 }
75
b4b39061
AG
76 wil->n_msi = use_msi;
77
2bdc0700
VK
78 if ((wil->n_msi == 0) && msi_only) {
79 wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
80 rc = -ENODEV;
81 goto stop_master;
82 }
83
2be7d22f
VK
84 rc = wil6210_init_irq(wil, pdev->irq);
85 if (rc)
86 goto stop_master;
87
88 /* need reset here to obtain MAC */
097638a0 89 mutex_lock(&wil->mutex);
2be7d22f 90 rc = wil_reset(wil);
097638a0 91 mutex_unlock(&wil->mutex);
94b7b64c
VK
92 if (debug_fw)
93 rc = 0;
2be7d22f
VK
94 if (rc)
95 goto release_irq;
96
97 return 0;
98
99 release_irq:
100 wil6210_fini_irq(wil, pdev->irq);
101 /* safe to call if no MSI */
102 pci_disable_msi(pdev);
103 stop_master:
104 pci_clear_master(pdev);
105 return rc;
106}
107
108static int wil_if_pcie_disable(struct wil6210_priv *wil)
109{
110 struct pci_dev *pdev = wil->pdev;
111
9cf10d62
VK
112 wil_dbg_misc(wil, "%s()\n", __func__);
113
2be7d22f
VK
114 pci_clear_master(pdev);
115 /* disable and release IRQ */
116 wil6210_fini_irq(wil, pdev->irq);
117 /* safe to call if no MSI */
118 pci_disable_msi(pdev);
119 /* TODO: disable HW */
120
121 return 0;
122}
123
124static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
125{
126 struct wil6210_priv *wil;
127 struct device *dev = &pdev->dev;
128 void __iomem *csr;
6508281b 129 struct wil_board *board = (struct wil_board *)id->driver_data;
2be7d22f
VK
130 int rc;
131
132 /* check HW */
6508281b
VK
133 dev_info(&pdev->dev, WIL_NAME
134 " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name,
2be7d22f
VK
135 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
136
137 if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
138 dev_err(&pdev->dev, "Not " WIL_NAME "? "
139 "BAR0 size is %lu while expecting %lu\n",
140 (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE);
141 return -ENODEV;
142 }
143
144 rc = pci_enable_device(pdev);
145 if (rc) {
2bdc0700
VK
146 dev_err(&pdev->dev,
147 "pci_enable_device failed, retry with MSI only\n");
148 /* Work around for platforms that can't allocate IRQ:
149 * retry with MSI only
150 */
151 pdev->msi_enabled = 1;
152 rc = pci_enable_device(pdev);
2be7d22f 153 }
2bdc0700
VK
154 if (rc)
155 return -ENODEV;
2be7d22f
VK
156 /* rollback to err_disable_pdev */
157
158 rc = pci_request_region(pdev, 0, WIL_NAME);
159 if (rc) {
160 dev_err(&pdev->dev, "pci_request_region failed\n");
161 goto err_disable_pdev;
162 }
163 /* rollback to err_release_reg */
164
165 csr = pci_ioremap_bar(pdev, 0);
166 if (!csr) {
167 dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
168 rc = -ENODEV;
169 goto err_release_reg;
170 }
171 /* rollback to err_iounmap */
39c52ee8 172 dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr);
2be7d22f
VK
173
174 wil = wil_if_alloc(dev, csr);
175 if (IS_ERR(wil)) {
176 rc = (int)PTR_ERR(wil);
177 dev_err(dev, "wil_if_alloc failed: %d\n", rc);
178 goto err_iounmap;
179 }
180 /* rollback to if_free */
181
182 pci_set_drvdata(pdev, wil);
183 wil->pdev = pdev;
6508281b 184 wil->board = board;
2be7d22f 185
f4b5a803 186 wil6210_clear_irq(wil);
f772ebfb
VK
187
188 wil->platform_handle =
189 wil_platform_init(&pdev->dev, &wil->platform_ops);
190
2be7d22f
VK
191 /* FW should raise IRQ when ready */
192 rc = wil_if_pcie_enable(wil);
193 if (rc) {
194 wil_err(wil, "Enable device failed\n");
195 goto if_free;
196 }
197 /* rollback to bus_disable */
198
199 rc = wil_if_add(wil);
200 if (rc) {
201 wil_err(wil, "wil_if_add failed: %d\n", rc);
202 goto bus_disable;
203 }
204
205 wil6210_debugfs_init(wil);
206
207 /* check FW is alive */
208 wmi_echo(wil);
209
210 return 0;
211
212 bus_disable:
213 wil_if_pcie_disable(wil);
214 if_free:
f772ebfb
VK
215 if (wil->platform_ops.uninit)
216 wil->platform_ops.uninit(wil->platform_handle);
2be7d22f
VK
217 wil_if_free(wil);
218 err_iounmap:
219 pci_iounmap(pdev, csr);
220 err_release_reg:
221 pci_release_region(pdev, 0);
222 err_disable_pdev:
223 pci_disable_device(pdev);
224
225 return rc;
226}
227
228static void wil_pcie_remove(struct pci_dev *pdev)
229{
230 struct wil6210_priv *wil = pci_get_drvdata(pdev);
560ce308 231 void __iomem *csr = wil->csr;
2be7d22f 232
9cf10d62
VK
233 wil_dbg_misc(wil, "%s()\n", __func__);
234
2be7d22f 235 wil6210_debugfs_remove(wil);
2be7d22f 236 wil_if_remove(wil);
f172b563 237 wil_if_pcie_disable(wil);
f772ebfb
VK
238 if (wil->platform_ops.uninit)
239 wil->platform_ops.uninit(wil->platform_handle);
2be7d22f 240 wil_if_free(wil);
560ce308 241 pci_iounmap(pdev, csr);
2be7d22f
VK
242 pci_release_region(pdev, 0);
243 pci_disable_device(pdev);
2be7d22f
VK
244}
245
6508281b
VK
246static const struct wil_board wil_board_marlon = {
247 .board = WIL_BOARD_MARLON,
248 .name = "marlon",
249};
250
251static const struct wil_board wil_board_sparrow = {
252 .board = WIL_BOARD_SPARROW,
253 .name = "sparrow",
254};
255
256static const struct pci_device_id wil6210_pcie_ids[] = {
257 { PCI_DEVICE(0x1ae9, 0x0301),
258 .driver_data = (kernel_ulong_t)&wil_board_marlon },
259 { PCI_DEVICE(0x1ae9, 0x0310),
260 .driver_data = (kernel_ulong_t)&wil_board_sparrow },
6afd6005
VK
261 { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
262 .driver_data = (kernel_ulong_t)&wil_board_sparrow },
2be7d22f
VK
263 { /* end: all zeroes */ },
264};
265MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
266
267static struct pci_driver wil6210_driver = {
268 .probe = wil_pcie_probe,
269 .remove = wil_pcie_remove,
270 .id_table = wil6210_pcie_ids,
271 .name = WIL_NAME,
272};
273
274module_pci_driver(wil6210_driver);
275
276MODULE_LICENSE("Dual BSD/GPL");
277MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
278MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card");